mirror of
https://github.com/mpv-player/mpv
synced 2024-08-24 07:21:49 +02:00
libmpdemux: remove demux_real, demux_viv, demux_audio
libavformat replaces demux_audio completely. I don't know/care what vivo (demux_viv) is. libavformat has a Real demuxer; it seems it works slightly better, with a different set of bugs.
This commit is contained in:
parent
fc2ea37694
commit
8ca3ec1562
4
Makefile
4
Makefile
@ -253,7 +253,6 @@ SRCS_COMMON = asxparser.c \
|
||||
libmpdemux/aviprint.c \
|
||||
libmpdemux/demuxer.c \
|
||||
libmpdemux/demux_asf.c \
|
||||
libmpdemux/demux_audio.c \
|
||||
libmpdemux/demux_avi.c \
|
||||
libmpdemux/demux_demuxers.c \
|
||||
libmpdemux/demux_edl.c \
|
||||
@ -263,9 +262,6 @@ SRCS_COMMON = asxparser.c \
|
||||
libmpdemux/demux_mkv.c \
|
||||
libmpdemux/demux_rawaudio.c \
|
||||
libmpdemux/demux_rawvideo.c \
|
||||
libmpdemux/demux_realaud.c \
|
||||
libmpdemux/demux_real.c \
|
||||
libmpdemux/demux_viv.c \
|
||||
libmpdemux/ebml.c \
|
||||
libmpdemux/extension.c \
|
||||
libmpdemux/mf.c \
|
||||
|
@ -204,31 +204,8 @@ const m_option_t scaler_filter_conf[]={
|
||||
{NULL, NULL, 0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
/* VIVO demuxer options: */
|
||||
extern int vivo_param_version;
|
||||
extern char *vivo_param_acodec;
|
||||
extern int vivo_param_abitrate;
|
||||
extern int vivo_param_samplerate;
|
||||
extern int vivo_param_bytesperblock;
|
||||
extern int vivo_param_width;
|
||||
extern int vivo_param_height;
|
||||
extern int vivo_param_vformat;
|
||||
extern char *dvd_device, *cdrom_device;
|
||||
|
||||
const m_option_t vivoopts_conf[]={
|
||||
{"version", &vivo_param_version, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
/* audio options */
|
||||
{"acodec", &vivo_param_acodec, CONF_TYPE_STRING, 0, 0, 0, NULL},
|
||||
{"abitrate", &vivo_param_abitrate, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
{"samplerate", &vivo_param_samplerate, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
{"bytesperblock", &vivo_param_bytesperblock, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
/* video options */
|
||||
{"width", &vivo_param_width, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
{"height", &vivo_param_height, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
{"vformat", &vivo_param_vformat, CONF_TYPE_INT, 0, 0, 0, NULL},
|
||||
{NULL, NULL, 0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
extern int mf_w;
|
||||
extern int mf_h;
|
||||
extern double mf_fps;
|
||||
@ -485,7 +462,6 @@ const m_option_t common_opts[] = {
|
||||
#ifdef CONFIG_PVR
|
||||
{"pvr", (void *) pvropts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
|
||||
#endif /* CONFIG_PVR */
|
||||
{"vivo", (void *) vivoopts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
|
||||
#ifdef CONFIG_DVBIN
|
||||
{"dvbin", (void *) dvbin_opts_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
|
||||
#endif
|
||||
|
@ -1,830 +0,0 @@
|
||||
/*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libavutil/intreadwrite.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "options.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "aviprint.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
#include "genres.h"
|
||||
#include "mp3_hdr.h"
|
||||
|
||||
#define MP3 1
|
||||
#define WAV 2
|
||||
#define fLaC 3
|
||||
|
||||
|
||||
#define HDR_SIZE 4
|
||||
|
||||
typedef struct da_priv {
|
||||
int frmt;
|
||||
double next_pts;
|
||||
} da_priv_t;
|
||||
|
||||
//! rather arbitrary value for maximum length of wav-format headers
|
||||
#define MAX_WAVHDR_LEN (1 * 1024 * 1024)
|
||||
|
||||
//! how many valid frames in a row we need before accepting as valid MP3
|
||||
#define MIN_MP3_HDRS 12
|
||||
|
||||
//! Used to describe a potential (chain of) MP3 headers we found
|
||||
typedef struct mp3_hdr {
|
||||
off_t frame_pos; // start of first frame in this "chain" of headers
|
||||
off_t next_frame_pos; // here we expect the next header with same parameters
|
||||
int mp3_chans;
|
||||
int mp3_freq;
|
||||
int mpa_spf;
|
||||
int mpa_layer;
|
||||
int mpa_br;
|
||||
int cons_hdrs; // if this reaches MIN_MP3_HDRS we accept as MP3 file
|
||||
struct mp3_hdr *next;
|
||||
} mp3_hdr_t;
|
||||
|
||||
/**
|
||||
* \brief free a list of MP3 header descriptions
|
||||
* \param list pointer to the head-of-list pointer
|
||||
*/
|
||||
static void free_mp3_hdrs(mp3_hdr_t **list) {
|
||||
mp3_hdr_t *tmp;
|
||||
while (*list) {
|
||||
tmp = (*list)->next;
|
||||
free(*list);
|
||||
*list = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief add another potential MP3 header to our list
|
||||
* If it fits into an existing chain this one is expanded otherwise
|
||||
* a new one is created.
|
||||
* All entries that expected a MP3 header before the current position
|
||||
* are discarded.
|
||||
* The list is expected to be and will be kept sorted by next_frame_pos
|
||||
* and when those are equal by frame_pos.
|
||||
* \param list pointer to the head-of-list pointer
|
||||
* \param st_pos stream position where the described header starts
|
||||
* \param mp3_chans number of channels as specified by the header (*)
|
||||
* \param mp3_freq sampling frequency as specified by the header (*)
|
||||
* \param mpa_spf frame size as specified by the header
|
||||
* \param mpa_layer layer type ("version") as specified by the header (*)
|
||||
* \param mpa_br bitrate as specified by the header
|
||||
* \param mp3_flen length of the frame as specified by the header
|
||||
* \return If non-null the current file is accepted as MP3 and the
|
||||
* mp3_hdr struct describing the valid chain is returned. Must be
|
||||
* freed independent of the list.
|
||||
*
|
||||
* parameters marked by (*) must be the same for all headers in the same chain
|
||||
*/
|
||||
static mp3_hdr_t *add_mp3_hdr(mp3_hdr_t **list, off_t st_pos,
|
||||
int mp3_chans, int mp3_freq, int mpa_spf,
|
||||
int mpa_layer, int mpa_br, int mp3_flen) {
|
||||
mp3_hdr_t *tmp;
|
||||
int in_list = 0;
|
||||
while (*list && (*list)->next_frame_pos <= st_pos) {
|
||||
if (((*list)->next_frame_pos < st_pos) || ((*list)->mp3_chans != mp3_chans)
|
||||
|| ((*list)->mp3_freq != mp3_freq) || ((*list)->mpa_layer != mpa_layer) ) {
|
||||
// wasn't valid!
|
||||
tmp = (*list)->next;
|
||||
free(*list);
|
||||
*list = tmp;
|
||||
} else {
|
||||
(*list)->cons_hdrs++;
|
||||
(*list)->next_frame_pos = st_pos + mp3_flen;
|
||||
(*list)->mpa_spf = mpa_spf;
|
||||
(*list)->mpa_br = mpa_br;
|
||||
if ((*list)->cons_hdrs >= MIN_MP3_HDRS) {
|
||||
// copy the valid entry, so that the list can be easily freed
|
||||
tmp = malloc(sizeof(mp3_hdr_t));
|
||||
memcpy(tmp, *list, sizeof(mp3_hdr_t));
|
||||
tmp->next = NULL;
|
||||
return tmp;
|
||||
}
|
||||
in_list = 1;
|
||||
list = &((*list)->next);
|
||||
}
|
||||
}
|
||||
if (!in_list) { // does not belong into an existing chain, insert
|
||||
// find right position to insert to keep sorting
|
||||
while (*list && (*list)->next_frame_pos <= st_pos + mp3_flen)
|
||||
list = &((*list)->next);
|
||||
tmp = malloc(sizeof(mp3_hdr_t));
|
||||
tmp->frame_pos = st_pos;
|
||||
tmp->next_frame_pos = st_pos + mp3_flen;
|
||||
tmp->mp3_chans = mp3_chans;
|
||||
tmp->mp3_freq = mp3_freq;
|
||||
tmp->mpa_spf = mpa_spf;
|
||||
tmp->mpa_layer = mpa_layer;
|
||||
tmp->mpa_br = mpa_br;
|
||||
tmp->cons_hdrs = 1;
|
||||
tmp->next = *list;
|
||||
*list = tmp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0 /* this code is a mess, clean it up before reenabling */
|
||||
#define FLAC_SIGNATURE_SIZE 4
|
||||
#define FLAC_STREAMINFO_SIZE 34
|
||||
#define FLAC_SEEKPOINT_SIZE 18
|
||||
|
||||
enum {
|
||||
FLAC_STREAMINFO = 0,
|
||||
FLAC_PADDING,
|
||||
FLAC_APPLICATION,
|
||||
FLAC_SEEKTABLE,
|
||||
FLAC_VORBIS_COMMENT,
|
||||
FLAC_CUESHEET
|
||||
} flac_preamble_t;
|
||||
|
||||
static void
|
||||
get_flac_metadata (demuxer_t* demuxer)
|
||||
{
|
||||
uint8_t preamble[4];
|
||||
unsigned int blk_len;
|
||||
stream_t *s = demuxer->stream;
|
||||
|
||||
/* file is qualified; skip over the signature bytes in the stream */
|
||||
stream_seek (s, 4);
|
||||
|
||||
/* loop through the metadata blocks; use a do-while construct since there
|
||||
* will always be 1 metadata block */
|
||||
do {
|
||||
int r;
|
||||
|
||||
r = stream_read (s, (char *) preamble, FLAC_SIGNATURE_SIZE);
|
||||
if (r != FLAC_SIGNATURE_SIZE)
|
||||
return;
|
||||
|
||||
blk_len = AV_RB24(preamble + 1);
|
||||
|
||||
switch (preamble[0] & 0x7F)
|
||||
{
|
||||
case FLAC_VORBIS_COMMENT:
|
||||
{
|
||||
/* For a description of the format please have a look at */
|
||||
/* http://www.xiph.org/vorbis/doc/v-comment.html */
|
||||
|
||||
uint32_t length, comment_list_len;
|
||||
char comments[blk_len];
|
||||
uint8_t *ptr = comments;
|
||||
char *comment;
|
||||
int cn;
|
||||
char c;
|
||||
|
||||
if (stream_read (s, comments, blk_len) == blk_len)
|
||||
{
|
||||
length = AV_RL32(ptr);
|
||||
ptr += 4 + length;
|
||||
|
||||
comment_list_len = AV_RL32(ptr);
|
||||
ptr += 4;
|
||||
|
||||
cn = 0;
|
||||
for (; cn < comment_list_len; cn++)
|
||||
{
|
||||
length = AV_RL32(ptr);
|
||||
ptr += 4;
|
||||
|
||||
comment = ptr;
|
||||
if (&comment[length] < comments || &comment[length] >= &comments[blk_len])
|
||||
return;
|
||||
c = comment[length];
|
||||
comment[length] = 0;
|
||||
|
||||
if (!strncasecmp ("TITLE=", comment, 6) && (length - 6 > 0))
|
||||
demux_info_add (demuxer, "Title", comment + 6);
|
||||
else if (!strncasecmp ("ARTIST=", comment, 7) && (length - 7 > 0))
|
||||
demux_info_add (demuxer, "Artist", comment + 7);
|
||||
else if (!strncasecmp ("ALBUM=", comment, 6) && (length - 6 > 0))
|
||||
demux_info_add (demuxer, "Album", comment + 6);
|
||||
else if (!strncasecmp ("DATE=", comment, 5) && (length - 5 > 0))
|
||||
demux_info_add (demuxer, "Year", comment + 5);
|
||||
else if (!strncasecmp ("GENRE=", comment, 6) && (length - 6 > 0))
|
||||
demux_info_add (demuxer, "Genre", comment + 6);
|
||||
else if (!strncasecmp ("Comment=", comment, 8) && (length - 8 > 0))
|
||||
demux_info_add (demuxer, "Comment", comment + 8);
|
||||
else if (!strncasecmp ("TRACKNUMBER=", comment, 12)
|
||||
&& (length - 12 > 0))
|
||||
{
|
||||
char buf[31];
|
||||
buf[30] = '\0';
|
||||
sprintf (buf, "%d", atoi (comment + 12));
|
||||
demux_info_add(demuxer, "Track", buf);
|
||||
}
|
||||
comment[length] = c;
|
||||
|
||||
ptr += length;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FLAC_STREAMINFO:
|
||||
case FLAC_PADDING:
|
||||
case FLAC_APPLICATION:
|
||||
case FLAC_SEEKTABLE:
|
||||
case FLAC_CUESHEET:
|
||||
default:
|
||||
/* 6-127 are presently reserved */
|
||||
stream_skip (s, blk_len);
|
||||
break;
|
||||
}
|
||||
} while ((preamble[0] & 0x80) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Determine the number of frames of a file encoded with
|
||||
* variable bitrate mode (VBR).
|
||||
*
|
||||
* @param s stream to be read
|
||||
* @param off offset in stream to start reading from
|
||||
*
|
||||
* @return 0 (error or no variable bitrate mode) or number of frames
|
||||
*/
|
||||
static unsigned int mp3_vbr_frames(stream_t *s, off_t off) {
|
||||
static const int xing_offset[2][2] = {{32, 17}, {17, 9}};
|
||||
unsigned int data;
|
||||
unsigned char hdr[4];
|
||||
int framesize, chans, spf, layer;
|
||||
|
||||
if ((s->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK) {
|
||||
|
||||
if (!stream_seek(s, off)) return 0;
|
||||
|
||||
data = stream_read_dword(s);
|
||||
hdr[0] = data >> 24;
|
||||
hdr[1] = data >> 16;
|
||||
hdr[2] = data >> 8;
|
||||
hdr[3] = data;
|
||||
|
||||
if (!mp_check_mp3_header(data)) return 0;
|
||||
|
||||
framesize = mp_get_mp3_header(hdr, &chans, NULL, &spf, &layer, NULL);
|
||||
|
||||
if (framesize == -1 || layer != 3) return 0;
|
||||
|
||||
/* Xing / Info (at variable position: 32, 17 or 9 bytes after header) */
|
||||
|
||||
if (!stream_skip(s, xing_offset[spf < 1152][chans == 1])) return 0;
|
||||
|
||||
data = stream_read_dword(s);
|
||||
|
||||
if (data == MKBETAG('X','i','n','g') || data == MKBETAG('I','n','f','o')) {
|
||||
data = stream_read_dword(s);
|
||||
|
||||
if (data & 0x1) // frames field is present
|
||||
return stream_read_dword(s); // frames
|
||||
}
|
||||
|
||||
/* VBRI (at fixed position: 32 bytes after header) */
|
||||
|
||||
if (!stream_seek(s, off + 4 + 32)) return 0;
|
||||
|
||||
data = stream_read_dword(s);
|
||||
|
||||
if (data == MKBETAG('V','B','R','I')) {
|
||||
data = stream_read_word(s);
|
||||
|
||||
if (data == 1) { // check version
|
||||
if (!stream_skip(s, 8)) return 0; // skip delay, quality and bytes
|
||||
return stream_read_dword(s); // frames
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine the total size of an ID3v2 tag.
|
||||
*
|
||||
* @param maj_ver major version of the ID3v2 tag
|
||||
* @param s stream to be read, assumed to be positioned at revision byte
|
||||
*
|
||||
* @return 0 (error or malformed tag) or tag size
|
||||
*/
|
||||
static unsigned int id3v2_tag_size(uint8_t maj_ver, stream_t *s) {
|
||||
unsigned int header_footer_size;
|
||||
unsigned int size;
|
||||
int i;
|
||||
|
||||
if(stream_read_char(s) == 0xff)
|
||||
return 0;
|
||||
header_footer_size = ((stream_read_char(s) & 0x10) && maj_ver >= 4) ? 20 : 10;
|
||||
|
||||
size = 0;
|
||||
for(i = 0; i < 4; i++) {
|
||||
uint8_t data = stream_read_char(s);
|
||||
if (data & 0x80)
|
||||
return 0;
|
||||
size = size << 7 | data;
|
||||
}
|
||||
|
||||
return header_footer_size + size;
|
||||
}
|
||||
|
||||
static int demux_audio_open(demuxer_t* demuxer) {
|
||||
stream_t *s;
|
||||
sh_audio_t* sh_audio;
|
||||
uint8_t hdr[HDR_SIZE];
|
||||
int frmt = 0, n = 0, step;
|
||||
off_t st_pos = 0, next_frame_pos = 0;
|
||||
// mp3_hdrs list is sorted first by next_frame_pos and then by frame_pos
|
||||
mp3_hdr_t *mp3_hdrs = NULL, *mp3_found = NULL;
|
||||
da_priv_t* priv;
|
||||
double duration;
|
||||
int found_WAVE = 0;
|
||||
|
||||
s = demuxer->stream;
|
||||
|
||||
stream_read(s, hdr, HDR_SIZE);
|
||||
while(n < 30000 && !s->eof) {
|
||||
int mp3_freq, mp3_chans, mp3_flen, mpa_layer, mpa_spf, mpa_br;
|
||||
st_pos = stream_tell(s) - HDR_SIZE;
|
||||
step = 1;
|
||||
|
||||
if( hdr[0] == 'R' && hdr[1] == 'I' && hdr[2] == 'F' && hdr[3] == 'F' ) {
|
||||
stream_skip(s,4);
|
||||
if(s->eof)
|
||||
break;
|
||||
stream_read(s,hdr,4);
|
||||
if(s->eof)
|
||||
break;
|
||||
if(hdr[0] != 'W' || hdr[1] != 'A' || hdr[2] != 'V' || hdr[3] != 'E' )
|
||||
stream_skip(s,-8);
|
||||
else
|
||||
// We found wav header. Now we can have 'fmt ' or a mp3 header
|
||||
// empty the buffer
|
||||
step = 4;
|
||||
} else if( hdr[0] == 'I' && hdr[1] == 'D' && hdr[2] == '3' && hdr[3] >= 2 && hdr[3] != 0xff) {
|
||||
unsigned int len = id3v2_tag_size(hdr[3], s);
|
||||
if(len > 0)
|
||||
stream_skip(s,len-10);
|
||||
step = 4;
|
||||
} else if( found_WAVE && hdr[0] == 'f' && hdr[1] == 'm' && hdr[2] == 't' && hdr[3] == ' ' ) {
|
||||
frmt = WAV;
|
||||
break;
|
||||
} else if((mp3_flen = mp_get_mp3_header(hdr, &mp3_chans, &mp3_freq,
|
||||
&mpa_spf, &mpa_layer, &mpa_br)) > 0) {
|
||||
mp3_found = add_mp3_hdr(&mp3_hdrs, st_pos, mp3_chans, mp3_freq,
|
||||
mpa_spf, mpa_layer, mpa_br, mp3_flen);
|
||||
if (mp3_found) {
|
||||
frmt = MP3;
|
||||
break;
|
||||
}
|
||||
} else if( hdr[0] == 'f' && hdr[1] == 'L' && hdr[2] == 'a' && hdr[3] == 'C' ) {
|
||||
frmt = fLaC;
|
||||
if (!mp3_hdrs || mp3_hdrs->cons_hdrs < 3)
|
||||
break;
|
||||
}
|
||||
found_WAVE = hdr[0] == 'W' && hdr[1] == 'A' && hdr[2] == 'V' && hdr[3] == 'E';
|
||||
// Add here some other audio format detection
|
||||
if(step < HDR_SIZE)
|
||||
memmove(hdr,&hdr[step],HDR_SIZE-step);
|
||||
stream_read(s, &hdr[HDR_SIZE - step], step);
|
||||
n++;
|
||||
}
|
||||
|
||||
free_mp3_hdrs(&mp3_hdrs);
|
||||
|
||||
if(!frmt)
|
||||
return 0;
|
||||
|
||||
sh_audio = new_sh_audio(demuxer,0);
|
||||
|
||||
switch(frmt) {
|
||||
case MP3:
|
||||
sh_audio->format = (mp3_found->mpa_layer < 3 ? 0x50 : 0x55);
|
||||
demuxer->movi_start = mp3_found->frame_pos;
|
||||
demuxer->movi_end = s->end_pos;
|
||||
next_frame_pos = mp3_found->next_frame_pos;
|
||||
sh_audio->audio.dwSampleSize= 0;
|
||||
sh_audio->audio.dwScale = mp3_found->mpa_spf;
|
||||
sh_audio->audio.dwRate = mp3_found->mp3_freq;
|
||||
sh_audio->wf = malloc(sizeof(*sh_audio->wf));
|
||||
sh_audio->wf->wFormatTag = sh_audio->format;
|
||||
sh_audio->wf->nChannels = mp3_found->mp3_chans;
|
||||
sh_audio->wf->nSamplesPerSec = mp3_found->mp3_freq;
|
||||
sh_audio->wf->nAvgBytesPerSec = mp3_found->mpa_br * (1000 / 8);
|
||||
sh_audio->wf->nBlockAlign = mp3_found->mpa_spf;
|
||||
sh_audio->wf->wBitsPerSample = 16;
|
||||
sh_audio->wf->cbSize = 0;
|
||||
duration = (double) mp3_vbr_frames(s, demuxer->movi_start) * mp3_found->mpa_spf / mp3_found->mp3_freq;
|
||||
free(mp3_found);
|
||||
mp3_found = NULL;
|
||||
if(demuxer->movi_end && (s->flags & MP_STREAM_SEEK) == MP_STREAM_SEEK) {
|
||||
if(demuxer->movi_end >= 128) {
|
||||
stream_seek(s,demuxer->movi_end-128);
|
||||
stream_read(s,hdr,3);
|
||||
if(!memcmp(hdr,"TAG",3)) {
|
||||
char buf[31];
|
||||
uint8_t g;
|
||||
demuxer->movi_end -= 128;
|
||||
stream_read(s,buf,30);
|
||||
buf[30] = '\0';
|
||||
demux_info_add(demuxer,"Title",buf);
|
||||
stream_read(s,buf,30);
|
||||
buf[30] = '\0';
|
||||
demux_info_add(demuxer,"Artist",buf);
|
||||
stream_read(s,buf,30);
|
||||
buf[30] = '\0';
|
||||
demux_info_add(demuxer,"Album",buf);
|
||||
stream_read(s,buf,4);
|
||||
buf[4] = '\0';
|
||||
demux_info_add(demuxer,"Year",buf);
|
||||
stream_read(s,buf,30);
|
||||
buf[30] = '\0';
|
||||
demux_info_add(demuxer,"Comment",buf);
|
||||
if(buf[28] == 0 && buf[29] != 0) {
|
||||
uint8_t trk = (uint8_t)buf[29];
|
||||
sprintf(buf,"%d",trk);
|
||||
demux_info_add(demuxer,"Track",buf);
|
||||
}
|
||||
g = stream_read_char(s);
|
||||
demux_info_add(demuxer,"Genre",genres[g]);
|
||||
}
|
||||
}
|
||||
if(demuxer->movi_end >= 10) {
|
||||
stream_seek(s,demuxer->movi_end-10);
|
||||
stream_read(s,hdr,4);
|
||||
if(!memcmp(hdr,"3DI",3) && hdr[3] >= 4 && hdr[3] != 0xff) {
|
||||
unsigned int len = id3v2_tag_size(hdr[3], s);
|
||||
if(len > 0) {
|
||||
if(len > demuxer->movi_end - demuxer->movi_start) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"Audio demuxer: bad ID3v2 tag size: larger than stream (%u).\n",len);
|
||||
len = FFMIN(10,demuxer->movi_end-demuxer->movi_start);
|
||||
} else {
|
||||
stream_seek(s,demuxer->movi_end-len);
|
||||
stream_read(s,hdr,4);
|
||||
if(memcmp(hdr,"ID3",3) || hdr[3] < 4 || hdr[3] == 0xff || id3v2_tag_size(hdr[3], s) != len) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"Audio demuxer: damaged appended ID3v2 tag detected.\n");
|
||||
len = FFMIN(10,demuxer->movi_end-demuxer->movi_start);
|
||||
}
|
||||
}
|
||||
demuxer->movi_end -= len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (duration && demuxer->movi_end && demuxer->movi_end > demuxer->movi_start) sh_audio->wf->nAvgBytesPerSec = (demuxer->movi_end - demuxer->movi_start) / duration;
|
||||
sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec;
|
||||
break;
|
||||
case WAV: {
|
||||
unsigned int chunk_type;
|
||||
unsigned int chunk_size;
|
||||
WAVEFORMATEX* w;
|
||||
int l;
|
||||
l = stream_read_dword_le(s);
|
||||
if(l < 16) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"[demux_audio] Bad wav header length: too short (%d)!!!\n",l);
|
||||
l = 16;
|
||||
}
|
||||
if(l > MAX_WAVHDR_LEN) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"[demux_audio] Bad wav header length: too long (%d)!!!\n",l);
|
||||
l = 16;
|
||||
}
|
||||
sh_audio->wf = w = malloc(l > sizeof(*w) ? l : sizeof(*w));
|
||||
w->wFormatTag = sh_audio->format = stream_read_word_le(s);
|
||||
w->nChannels = sh_audio->channels = stream_read_word_le(s);
|
||||
w->nSamplesPerSec = sh_audio->samplerate = stream_read_dword_le(s);
|
||||
w->nAvgBytesPerSec = stream_read_dword_le(s);
|
||||
w->nBlockAlign = stream_read_word_le(s);
|
||||
w->wBitsPerSample = stream_read_word_le(s);
|
||||
sh_audio->samplesize = (w->wBitsPerSample + 7) / 8;
|
||||
w->cbSize = 0;
|
||||
sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec;
|
||||
l -= 16;
|
||||
if (l >= 2) {
|
||||
w->cbSize = stream_read_word_le(s);
|
||||
l -= 2;
|
||||
if (l < w->cbSize) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"[demux_audio] truncated extradata (%d < %d)\n",
|
||||
l,w->cbSize);
|
||||
w->cbSize = l;
|
||||
}
|
||||
stream_read(s,(char*)(w + 1),w->cbSize);
|
||||
l -= w->cbSize;
|
||||
if (w->wFormatTag == 0xfffe && w->cbSize >= 22)
|
||||
sh_audio->format = le2me_16(((WAVEFORMATEXTENSIBLE *)w)->SubFormat);
|
||||
}
|
||||
|
||||
if( mp_msg_test(MSGT_DEMUX,MSGL_V) ) print_wave_header(w, MSGL_V);
|
||||
if(l)
|
||||
stream_skip(s,l);
|
||||
do
|
||||
{
|
||||
chunk_type = stream_read_fourcc(demuxer->stream);
|
||||
chunk_size = stream_read_dword_le(demuxer->stream);
|
||||
if (chunk_type != mmioFOURCC('d', 'a', 't', 'a'))
|
||||
stream_skip(demuxer->stream, chunk_size);
|
||||
} while (!s->eof && chunk_type != mmioFOURCC('d', 'a', 't', 'a'));
|
||||
demuxer->movi_start = stream_tell(s);
|
||||
demuxer->movi_end = chunk_size ? demuxer->movi_start + chunk_size : s->end_pos;
|
||||
// printf("wav: %X .. %X\n",(int)demuxer->movi_start,(int)demuxer->movi_end);
|
||||
// Check if it contains dts audio
|
||||
if((w->wFormatTag == 0x01) && (w->nChannels == 2) && (w->nSamplesPerSec == 44100)) {
|
||||
unsigned char buf[16384]; // vlc uses 16384*4 (4 dts frames)
|
||||
unsigned int i;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
stream_read(s, buf, sizeof(buf));
|
||||
for (i = 0; i < sizeof(buf) - 5; i += 2) {
|
||||
// DTS, 14 bit, LE
|
||||
if((buf[i] == 0xff) && (buf[i+1] == 0x1f) && (buf[i+2] == 0x00) &&
|
||||
(buf[i+3] == 0xe8) && ((buf[i+4] & 0xfe) == 0xf0) && (buf[i+5] == 0x07)) {
|
||||
sh_audio->format = 0x2001;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[demux_audio] DTS audio in wav, 14 bit, LE\n");
|
||||
break;
|
||||
}
|
||||
// DTS, 14 bit, BE
|
||||
if((buf[i] == 0x1f) && (buf[i+1] == 0xff) && (buf[i+2] == 0xe8) &&
|
||||
(buf[i+3] == 0x00) && (buf[i+4] == 0x07) && ((buf[i+5] & 0xfe) == 0xf0)) {
|
||||
sh_audio->format = 0x2001;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[demux_audio] DTS audio in wav, 14 bit, BE\n");
|
||||
break;
|
||||
}
|
||||
// DTS, 16 bit, BE
|
||||
if((buf[i] == 0x7f) && (buf[i+1] == 0xfe) && (buf[i+2] == 0x80) &&
|
||||
(buf[i+3] == 0x01)) {
|
||||
sh_audio->format = 0x2001;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[demux_audio] DTS audio in wav, 16 bit, BE\n");
|
||||
break;
|
||||
}
|
||||
// DTS, 16 bit, LE
|
||||
if((buf[i] == 0xfe) && (buf[i+1] == 0x7f) && (buf[i+2] == 0x01) &&
|
||||
(buf[i+3] == 0x80)) {
|
||||
sh_audio->format = 0x2001;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[demux_audio] DTS audio in wav, 16 bit, LE\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sh_audio->format == 0x2001) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"[demux_audio] DTS sync offset = %u\n", i);
|
||||
}
|
||||
|
||||
}
|
||||
// All formats that have a parser will need it when stored in WAV
|
||||
sh_audio->needs_parsing = 1;
|
||||
stream_seek(s,demuxer->movi_start);
|
||||
} break;
|
||||
case fLaC:
|
||||
sh_audio->format = mmioFOURCC('f', 'L', 'a', 'C');
|
||||
demuxer->movi_start = stream_tell(s) - 4;
|
||||
demuxer->movi_end = s->end_pos;
|
||||
if (demuxer->movi_end > demuxer->movi_start) {
|
||||
// try to find out approx. bitrate
|
||||
int64_t size = demuxer->movi_end - demuxer->movi_start;
|
||||
int64_t num_samples;
|
||||
int32_t srate;
|
||||
stream_skip(s, 14);
|
||||
srate = stream_read_int24(s) >> 4;
|
||||
num_samples = stream_read_int24(s) << 16;
|
||||
num_samples |= stream_read_word(s);
|
||||
if (num_samples && srate)
|
||||
sh_audio->i_bps = size * srate / num_samples;
|
||||
}
|
||||
if (sh_audio->i_bps < 1) // guess value to prevent crash
|
||||
sh_audio->i_bps = 64 * 1024;
|
||||
sh_audio->needs_parsing = 1;
|
||||
// get_flac_metadata (demuxer);
|
||||
break;
|
||||
}
|
||||
|
||||
priv = malloc(sizeof(da_priv_t));
|
||||
priv->frmt = frmt;
|
||||
priv->next_pts = 0;
|
||||
demuxer->priv = priv;
|
||||
demuxer->audio->id = 0;
|
||||
demuxer->audio->sh = sh_audio;
|
||||
sh_audio->ds = demuxer->audio;
|
||||
sh_audio->samplerate = sh_audio->audio.dwRate;
|
||||
|
||||
if(stream_tell(s) != demuxer->movi_start)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "demux_audio: seeking from 0x%X to start pos 0x%X\n",
|
||||
(int)stream_tell(s), (int)demuxer->movi_start);
|
||||
stream_seek(s,demuxer->movi_start);
|
||||
if (stream_tell(s) != demuxer->movi_start) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "demux_audio: seeking failed, now at 0x%X!\n",
|
||||
(int)stream_tell(s));
|
||||
if (next_frame_pos) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "demux_audio: seeking to 0x%X instead\n",
|
||||
(int)next_frame_pos);
|
||||
stream_seek(s, next_frame_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"demux_audio: audio data 0x%X - 0x%X \n",(int)demuxer->movi_start,(int)demuxer->movi_end);
|
||||
|
||||
return DEMUXER_TYPE_AUDIO;
|
||||
}
|
||||
|
||||
|
||||
static int demux_audio_fill_buffer(demuxer_t *demux, demux_stream_t *ds) {
|
||||
int l;
|
||||
demux_packet_t* dp;
|
||||
sh_audio_t* sh_audio = ds->sh;
|
||||
da_priv_t* priv = demux->priv;
|
||||
double this_pts = priv->next_pts;
|
||||
stream_t* s = demux->stream;
|
||||
|
||||
if(s->eof)
|
||||
return 0;
|
||||
|
||||
switch(priv->frmt) {
|
||||
case MP3 :
|
||||
while(1) {
|
||||
uint8_t hdr[4];
|
||||
stream_read(s,hdr,4);
|
||||
if (s->eof)
|
||||
return 0;
|
||||
l = mp_decode_mp3_header(hdr);
|
||||
if(l < 0) {
|
||||
if (demux->movi_end && stream_tell(s) >= demux->movi_end)
|
||||
return 0; // might be ID3 tag, i.e. EOF
|
||||
stream_skip(s,-3);
|
||||
} else {
|
||||
dp = new_demux_packet(l);
|
||||
memcpy(dp->buffer,hdr,4);
|
||||
if (stream_read(s,dp->buffer + 4,l-4) != l-4)
|
||||
{
|
||||
free_demux_packet(dp);
|
||||
return 0;
|
||||
}
|
||||
priv->next_pts += sh_audio->audio.dwScale/(double)sh_audio->samplerate;
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
case WAV : {
|
||||
unsigned align = sh_audio->wf->nBlockAlign;
|
||||
l = sh_audio->wf->nAvgBytesPerSec;
|
||||
if (l <= 0) l = 65536;
|
||||
if (demux->movi_end && l > demux->movi_end - stream_tell(s)) {
|
||||
// do not read beyond end, there might be junk after data chunk
|
||||
l = demux->movi_end - stream_tell(s);
|
||||
if (l <= 0) return 0;
|
||||
}
|
||||
if (align)
|
||||
l = (l + align - 1) / align * align;
|
||||
dp = new_demux_packet(l);
|
||||
l = stream_read(s,dp->buffer,l);
|
||||
priv->next_pts += l/(double)sh_audio->i_bps;
|
||||
break;
|
||||
}
|
||||
case fLaC: {
|
||||
l = 65535;
|
||||
dp = new_demux_packet(l);
|
||||
l = stream_read(s,dp->buffer,l);
|
||||
priv->next_pts = MP_NOPTS_VALUE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mp_tmsg(MSGT_DEMUXER,MSGL_WARN,"Audio demuxer: unknown format %d.\n",priv->frmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
resize_demux_packet(dp, l);
|
||||
dp->pts = this_pts;
|
||||
ds_add_packet(ds, dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void high_res_mp3_seek(demuxer_t *demuxer,float time) {
|
||||
uint8_t hdr[4];
|
||||
int len,nf;
|
||||
da_priv_t* priv = demuxer->priv;
|
||||
sh_audio_t* sh = (sh_audio_t*)demuxer->audio->sh;
|
||||
|
||||
nf = time*sh->samplerate/sh->audio.dwScale;
|
||||
while(nf > 0) {
|
||||
stream_read(demuxer->stream,hdr,4);
|
||||
len = mp_decode_mp3_header(hdr);
|
||||
if(len < 0) {
|
||||
stream_skip(demuxer->stream,-3);
|
||||
continue;
|
||||
}
|
||||
stream_skip(demuxer->stream,len-4);
|
||||
priv->next_pts += sh->audio.dwScale/(double)sh->samplerate;
|
||||
nf--;
|
||||
}
|
||||
}
|
||||
|
||||
static void demux_audio_seek(demuxer_t *demuxer,float rel_seek_secs,float audio_delay,int flags){
|
||||
struct MPOpts *opts = demuxer->opts;
|
||||
sh_audio_t* sh_audio;
|
||||
stream_t* s;
|
||||
int64_t base,pos;
|
||||
float len;
|
||||
da_priv_t* priv;
|
||||
|
||||
if(!(sh_audio = demuxer->audio->sh))
|
||||
return;
|
||||
s = demuxer->stream;
|
||||
priv = demuxer->priv;
|
||||
|
||||
if(priv->frmt == MP3 && opts->hr_mp3_seek && !(flags & SEEK_FACTOR)) {
|
||||
len = (flags & SEEK_ABSOLUTE) ? rel_seek_secs - priv->next_pts : rel_seek_secs;
|
||||
if(len < 0) {
|
||||
stream_seek(s,demuxer->movi_start);
|
||||
len = priv->next_pts + len;
|
||||
priv->next_pts = 0;
|
||||
}
|
||||
if(len > 0)
|
||||
high_res_mp3_seek(demuxer,len);
|
||||
return;
|
||||
}
|
||||
|
||||
base = flags&SEEK_ABSOLUTE ? demuxer->movi_start : stream_tell(s);
|
||||
if(flags&SEEK_FACTOR)
|
||||
pos = base + ((demuxer->movi_end - demuxer->movi_start)*rel_seek_secs);
|
||||
else
|
||||
pos = base + (rel_seek_secs*sh_audio->i_bps);
|
||||
|
||||
if(demuxer->movi_end && pos >= demuxer->movi_end) {
|
||||
pos = demuxer->movi_end;
|
||||
} else if(pos < demuxer->movi_start)
|
||||
pos = demuxer->movi_start;
|
||||
|
||||
priv->next_pts = (pos-demuxer->movi_start)/(double)sh_audio->i_bps;
|
||||
|
||||
switch(priv->frmt) {
|
||||
case WAV:
|
||||
pos -= (pos - demuxer->movi_start) %
|
||||
(sh_audio->wf->nBlockAlign ? sh_audio->wf->nBlockAlign :
|
||||
(sh_audio->channels * sh_audio->samplesize));
|
||||
break;
|
||||
}
|
||||
|
||||
stream_seek(s,pos);
|
||||
}
|
||||
|
||||
static void demux_close_audio(demuxer_t* demuxer) {
|
||||
da_priv_t* priv = demuxer->priv;
|
||||
|
||||
free(priv);
|
||||
}
|
||||
|
||||
static int demux_audio_control(demuxer_t *demuxer,int cmd, void *arg){
|
||||
sh_audio_t *sh_audio=demuxer->audio->sh;
|
||||
int audio_length = sh_audio->i_bps && demuxer->movi_end > demuxer->movi_start ?
|
||||
(demuxer->movi_end - demuxer->movi_start) / sh_audio->i_bps : 0;
|
||||
da_priv_t* priv = demuxer->priv;
|
||||
|
||||
switch(cmd) {
|
||||
case DEMUXER_CTRL_GET_TIME_LENGTH:
|
||||
if (audio_length<=0) return DEMUXER_CTRL_DONTKNOW;
|
||||
*((double *)arg)=(double)audio_length;
|
||||
return DEMUXER_CTRL_GUESS;
|
||||
|
||||
case DEMUXER_CTRL_GET_PERCENT_POS:
|
||||
if (audio_length<=0)
|
||||
return DEMUXER_CTRL_DONTKNOW;
|
||||
*((int *)arg)=(int)( (priv->next_pts*100) / audio_length);
|
||||
return DEMUXER_CTRL_OK;
|
||||
|
||||
default:
|
||||
return DEMUXER_CTRL_NOTIMPL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_audio = {
|
||||
"Audio demuxer",
|
||||
"audio",
|
||||
"Audio only",
|
||||
"?",
|
||||
"Audio only files",
|
||||
DEMUXER_TYPE_AUDIO,
|
||||
0, // unsafe autodetect
|
||||
demux_audio_open,
|
||||
demux_audio_fill_buffer,
|
||||
NULL,
|
||||
demux_close_audio,
|
||||
demux_audio_seek,
|
||||
demux_audio_control
|
||||
};
|
@ -46,7 +46,7 @@
|
||||
#include "stheader.h"
|
||||
#include "ebml.h"
|
||||
#include "matroska.h"
|
||||
#include "demux_real.h"
|
||||
//#include "demux_real.h"
|
||||
|
||||
#include "mp_msg.h"
|
||||
|
||||
@ -1814,6 +1814,54 @@ static int demux_mkv_read_block_lacing(uint8_t *buffer, uint64_t *size,
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define SKIP_BITS(n) buffer<<=n
|
||||
#define SHOW_BITS(n) ((buffer)>>(32-(n)))
|
||||
|
||||
static double real_fix_timestamp(unsigned char *buf, unsigned int timestamp, unsigned int format, int64_t *kf_base, int *kf_pts, double *pts){
|
||||
double v_pts;
|
||||
unsigned char *s = buf + 1 + (*buf+1)*8;
|
||||
uint32_t buffer= (s[0]<<24) + (s[1]<<16) + (s[2]<<8) + s[3];
|
||||
unsigned int kf=timestamp;
|
||||
int pict_type;
|
||||
|
||||
if(format==mmioFOURCC('R','V','3','0') || format==mmioFOURCC('R','V','4','0')){
|
||||
if(format==mmioFOURCC('R','V','3','0')){
|
||||
SKIP_BITS(3);
|
||||
pict_type= SHOW_BITS(2);
|
||||
SKIP_BITS(2 + 7);
|
||||
}else{
|
||||
SKIP_BITS(1);
|
||||
pict_type= SHOW_BITS(2);
|
||||
SKIP_BITS(2 + 7 + 3);
|
||||
}
|
||||
kf= SHOW_BITS(13); // kf= 2*SHOW_BITS(12);
|
||||
// if(pict_type==0)
|
||||
if(pict_type<=1){
|
||||
// I frame, sync timestamps:
|
||||
*kf_base=(int64_t)timestamp-kf;
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2,"\nTS: base=%08"PRIX64"\n",*kf_base);
|
||||
kf=timestamp;
|
||||
} else {
|
||||
// P/B frame, merge timestamps:
|
||||
int64_t tmp=(int64_t)timestamp-*kf_base;
|
||||
kf|=tmp&(~0x1fff); // combine with packet timestamp
|
||||
if(kf<tmp-4096) kf+=8192; else // workaround wrap-around problems
|
||||
if(kf>tmp+4096) kf-=8192;
|
||||
kf+=*kf_base;
|
||||
}
|
||||
if(pict_type != 3){ // P || I frame -> swap timestamps
|
||||
unsigned int tmp=kf;
|
||||
kf=*kf_pts;
|
||||
*kf_pts=tmp;
|
||||
// if(kf<=tmp) kf=0;
|
||||
}
|
||||
}
|
||||
v_pts=kf*0.001f;
|
||||
// if(pts && (v_pts<*pts || !kf)) v_pts=*pts+frametime;
|
||||
if(pts) *pts=v_pts;
|
||||
return v_pts;
|
||||
}
|
||||
|
||||
static void handle_realvideo(demuxer_t *demuxer, mkv_track_t *track,
|
||||
uint8_t *buffer, uint32_t size, bool keyframe)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,28 +0,0 @@
|
||||
/*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_DEMUX_REAL_H
|
||||
#define MPLAYER_DEMUX_REAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
double real_fix_timestamp(unsigned char *buf, unsigned int timestamp,
|
||||
unsigned int format, int64_t *kf_base,
|
||||
int *kf_pts, double *pts);
|
||||
|
||||
#endif /* MPLAYER_DEMUX_REAL_H */
|
@ -1,375 +0,0 @@
|
||||
/*
|
||||
* Realaudio demuxer
|
||||
* copyright (c) 2003, 2005 Roberto Togni
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "aviprint.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
|
||||
#define FOURCC_DOTRA mmioFOURCC('.','r','a', 0xfd)
|
||||
#define FOURCC_144 mmioFOURCC('1','4','_','4')
|
||||
#define FOURCC_288 mmioFOURCC('2','8','_','8')
|
||||
#define FOURCC_DNET mmioFOURCC('d','n','e','t')
|
||||
#define FOURCC_LPCJ mmioFOURCC('l','p','c','J')
|
||||
#define FOURCC_SIPR mmioFOURCC('s','i','p','r')
|
||||
#define INTLID_INT4 mmioFOURCC('I','n','t','4')
|
||||
#define INTLID_SIPR mmioFOURCC('s','i','p','r')
|
||||
|
||||
|
||||
static unsigned char sipr_swaps[38][2]={
|
||||
{0,63},{1,22},{2,44},{3,90},{5,81},{7,31},{8,86},{9,58},{10,36},{12,68},
|
||||
{13,39},{14,73},{15,53},{16,69},{17,57},{19,88},{20,34},{21,71},{24,46},
|
||||
{25,94},{26,54},{28,75},{29,50},{32,70},{33,92},{35,74},{38,85},{40,56},
|
||||
{42,87},{43,65},{45,59},{48,79},{49,93},{51,89},{55,95},{61,76},{67,83},
|
||||
{77,80} };
|
||||
|
||||
// Map flavour to bytes per second
|
||||
static int sipr_fl2bps[4] = {813, 1062, 625, 2000}; // 6.5, 8.5, 5, 16 kbit per second
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned short version;
|
||||
unsigned int dotranum;
|
||||
unsigned int data_size;
|
||||
unsigned short version2;
|
||||
unsigned int hdr_size;
|
||||
unsigned short codec_flavor;
|
||||
unsigned int coded_framesize;
|
||||
unsigned short sub_packet_h;
|
||||
unsigned short frame_size;
|
||||
unsigned short sub_packet_size;
|
||||
unsigned intl_id;
|
||||
unsigned char *audio_buf;
|
||||
} ra_priv_t;
|
||||
|
||||
|
||||
|
||||
static int ra_check_file(demuxer_t* demuxer)
|
||||
{
|
||||
unsigned int chunk_id;
|
||||
|
||||
chunk_id = stream_read_dword_le(demuxer->stream);
|
||||
if (chunk_id == FOURCC_DOTRA)
|
||||
return DEMUXER_TYPE_REALAUDIO;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// return value:
|
||||
// 0 = EOF or no stream found
|
||||
// 1 = successfully read a packet
|
||||
static int demux_ra_fill_buffer(demuxer_t *demuxer, demux_stream_t *dsds)
|
||||
{
|
||||
ra_priv_t *ra_priv = demuxer->priv;
|
||||
int len;
|
||||
demux_stream_t *ds = demuxer->audio;
|
||||
sh_audio_t *sh = ds->sh;
|
||||
WAVEFORMATEX *wf = sh->wf;
|
||||
demux_packet_t *dp;
|
||||
int x, y;
|
||||
|
||||
if (demuxer->stream->eof)
|
||||
return 0;
|
||||
|
||||
len = wf->nBlockAlign;
|
||||
demuxer->filepos = stream_tell(demuxer->stream);
|
||||
|
||||
if ((ra_priv->intl_id == INTLID_INT4) || (ra_priv->intl_id == INTLID_SIPR)) {
|
||||
if (ra_priv->intl_id == INTLID_SIPR) {
|
||||
int n;
|
||||
int bs = ra_priv->sub_packet_h * ra_priv->frame_size * 2 / 96; // nibbles per subpacket
|
||||
stream_read(demuxer->stream, ra_priv->audio_buf, ra_priv->sub_packet_h * ra_priv->frame_size);
|
||||
// Perform reordering
|
||||
for(n = 0; n < 38; n++) {
|
||||
int j;
|
||||
int i = bs * sipr_swaps[n][0];
|
||||
int o = bs * sipr_swaps[n][1];
|
||||
// swap nibbles of block 'i' with 'o' TODO: optimize
|
||||
for(j = 0; j < bs; j++) {
|
||||
int x = (i & 1) ? (ra_priv->audio_buf[i >> 1] >> 4) : (ra_priv->audio_buf[i >> 1] & 0x0F);
|
||||
int y = (o & 1) ? (ra_priv->audio_buf[o >> 1] >> 4) : (ra_priv->audio_buf[o >> 1] & 0x0F);
|
||||
if(o & 1)
|
||||
ra_priv->audio_buf[o >> 1] = (ra_priv->audio_buf[o >> 1] & 0x0F) | (x << 4);
|
||||
else
|
||||
ra_priv->audio_buf[o >> 1] = (ra_priv->audio_buf[o >> 1] & 0xF0) | x;
|
||||
if(i & 1)
|
||||
ra_priv->audio_buf[i >> 1] = (ra_priv->audio_buf[i >> 1] & 0x0F) | (y << 4);
|
||||
else
|
||||
ra_priv->audio_buf[i >> 1] = (ra_priv->audio_buf[i >> 1] & 0xF0) | y;
|
||||
++i; ++o;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < ra_priv->sub_packet_h; y++)
|
||||
for (x = 0; x < ra_priv->sub_packet_h / 2; x++)
|
||||
stream_read(demuxer->stream, ra_priv->audio_buf + x * 2 *ra_priv->frame_size +
|
||||
y * ra_priv->coded_framesize, ra_priv->coded_framesize);
|
||||
}
|
||||
// Release all the audio packets
|
||||
for (x = 0; x < ra_priv->sub_packet_h * ra_priv->frame_size / len; x++) {
|
||||
dp = new_demux_packet(len);
|
||||
memcpy(dp->buffer, ra_priv->audio_buf + x * len, len);
|
||||
dp->pts = x ? 0 : demuxer->filepos / ra_priv->data_size;
|
||||
dp->pos = demuxer->filepos; // all equal
|
||||
dp->keyframe = !x; // Mark first packet as keyframe
|
||||
ds_add_packet(ds, dp);
|
||||
}
|
||||
} else {
|
||||
dp = new_demux_packet(len);
|
||||
stream_read(demuxer->stream, dp->buffer, len);
|
||||
|
||||
dp->pts = demuxer->filepos / ra_priv->data_size;
|
||||
dp->pos = demuxer->filepos;
|
||||
ds_add_packet(ds, dp);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static demuxer_t* demux_open_ra(demuxer_t* demuxer)
|
||||
{
|
||||
ra_priv_t* ra_priv = demuxer->priv;
|
||||
sh_audio_t *sh;
|
||||
int i;
|
||||
char *buf;
|
||||
|
||||
if ((ra_priv = malloc(sizeof(ra_priv_t))) == NULL) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "[RealAudio] Can't allocate memory for private data.\n");
|
||||
return 0;
|
||||
}
|
||||
memset(ra_priv, 0, sizeof(ra_priv_t));
|
||||
|
||||
demuxer->priv = ra_priv;
|
||||
sh = new_sh_audio(demuxer, 0);
|
||||
demuxer->audio->id = 0;
|
||||
sh->ds=demuxer->audio;
|
||||
demuxer->audio->sh = sh;
|
||||
|
||||
ra_priv->version = stream_read_word(demuxer->stream);
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[RealAudio] File version: %d\n", ra_priv->version);
|
||||
if ((ra_priv->version < 3) || (ra_priv->version > 4)) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"[RealAudio] ra version %d is not supported yet, please "
|
||||
"contact MPlayer developers\n", ra_priv->version);
|
||||
return 0;
|
||||
}
|
||||
if (ra_priv->version == 3) {
|
||||
ra_priv->hdr_size = stream_read_word(demuxer->stream);
|
||||
stream_skip(demuxer->stream, 10);
|
||||
ra_priv->data_size = stream_read_dword(demuxer->stream);
|
||||
} else {
|
||||
stream_skip(demuxer->stream, 2);
|
||||
ra_priv->dotranum = stream_read_dword(demuxer->stream);
|
||||
ra_priv->data_size = stream_read_dword(demuxer->stream);
|
||||
ra_priv->version2 = stream_read_word(demuxer->stream);
|
||||
ra_priv->hdr_size = stream_read_dword(demuxer->stream);
|
||||
ra_priv->codec_flavor = stream_read_word(demuxer->stream);
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[RealAudio] Flavor: %d\n", ra_priv->codec_flavor);
|
||||
ra_priv->coded_framesize = stream_read_dword(demuxer->stream);
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[RealAudio] Coded frame size: %d\n", ra_priv->coded_framesize);
|
||||
stream_skip(demuxer->stream, 4); // data size?
|
||||
stream_skip(demuxer->stream, 8);
|
||||
ra_priv->sub_packet_h = stream_read_word(demuxer->stream);
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[RealAudio] Sub packet h: %d\n", ra_priv->sub_packet_h);
|
||||
ra_priv->frame_size = stream_read_word(demuxer->stream);
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[RealAudio] Frame size: %d\n", ra_priv->frame_size);
|
||||
ra_priv->sub_packet_size = stream_read_word(demuxer->stream);
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[RealAudio] Sub packet size: %d\n", ra_priv->sub_packet_size);
|
||||
stream_skip(demuxer->stream, 2);
|
||||
sh->samplerate = stream_read_word(demuxer->stream);
|
||||
stream_skip(demuxer->stream, 2);
|
||||
sh->samplesize = stream_read_word(demuxer->stream);
|
||||
sh->channels = stream_read_word(demuxer->stream);
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"[RealAudio] %d channel, %d bit, %dHz\n", sh->channels,
|
||||
sh->samplesize, sh->samplerate);
|
||||
i = stream_read_char(demuxer->stream);
|
||||
ra_priv->intl_id = stream_read_dword_le(demuxer->stream);
|
||||
if (i != 4) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"[RealAudio] Interleaver Id size is not 4 (%d), please report to "
|
||||
"MPlayer developers\n", i);
|
||||
stream_skip(demuxer->stream, i - 4);
|
||||
}
|
||||
i = stream_read_char(demuxer->stream);
|
||||
sh->format = stream_read_dword_le(demuxer->stream);
|
||||
if (i != 4) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"[RealAudio] FourCC size is not 4 (%d), please report to "
|
||||
"MPlayer developers\n", i);
|
||||
stream_skip(demuxer->stream, i - 4);
|
||||
}
|
||||
stream_skip(demuxer->stream, 3);
|
||||
}
|
||||
|
||||
if ((i = stream_read_char(demuxer->stream)) != 0) {
|
||||
buf = malloc(i+1);
|
||||
stream_read(demuxer->stream, buf, i);
|
||||
buf[i] = 0;
|
||||
demux_info_add(demuxer, "Title", buf);
|
||||
free(buf);
|
||||
}
|
||||
if ((i = stream_read_char(demuxer->stream)) != 0) {
|
||||
buf = malloc(i+1);
|
||||
stream_read(demuxer->stream, buf, i);
|
||||
buf[i] = 0;
|
||||
demux_info_add(demuxer, "Author", buf);
|
||||
free(buf);
|
||||
}
|
||||
if ((i = stream_read_char(demuxer->stream)) != 0) {
|
||||
buf = malloc(i+1);
|
||||
stream_read(demuxer->stream, buf, i);
|
||||
buf[i] = 0;
|
||||
demux_info_add(demuxer, "Copyright", buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
if ((i = stream_read_char(demuxer->stream)) != 0) {
|
||||
buf = malloc(i+1);
|
||||
stream_read(demuxer->stream, buf, i);
|
||||
buf[i] = 0;
|
||||
demux_info_add(demuxer, "Comment", buf);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
if (ra_priv->version == 3) {
|
||||
if(ra_priv->hdr_size + 8 > stream_tell(demuxer->stream)) {
|
||||
stream_skip(demuxer->stream, 1);
|
||||
i = stream_read_char(demuxer->stream);
|
||||
sh->format = stream_read_dword_le(demuxer->stream);
|
||||
if (i != 4) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"[RealAudio] FourCC size is not 4 (%d), please report to "
|
||||
"MPlayer developers\n", i);
|
||||
stream_skip(demuxer->stream, i - 4);
|
||||
}
|
||||
|
||||
if (sh->format != FOURCC_LPCJ) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"[RealAudio] Version 3 with FourCC %8x, please report to "
|
||||
"MPlayer developers\n", sh->format);
|
||||
}
|
||||
} else
|
||||
// If a stream does not have fourcc, let's assume it's 14.4
|
||||
sh->format = FOURCC_LPCJ;
|
||||
|
||||
sh->channels = 1;
|
||||
sh->samplesize = 16;
|
||||
sh->samplerate = 8000;
|
||||
ra_priv->frame_size = 240;
|
||||
sh->format = FOURCC_144;
|
||||
}
|
||||
|
||||
/* Fill WAVEFORMATEX */
|
||||
sh->wf = calloc(1, sizeof(*sh->wf));
|
||||
sh->wf->nChannels = sh->channels;
|
||||
sh->wf->wBitsPerSample = sh->samplesize;
|
||||
sh->wf->nSamplesPerSec = sh->samplerate;
|
||||
sh->wf->nAvgBytesPerSec = sh->samplerate*sh->samplesize/8;
|
||||
sh->wf->nBlockAlign = ra_priv->frame_size;
|
||||
sh->wf->cbSize = 0;
|
||||
sh->wf->wFormatTag = sh->format;
|
||||
|
||||
switch (sh->format) {
|
||||
case FOURCC_144:
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"Audio: 14_4\n");
|
||||
sh->wf->nBlockAlign = 0x14;
|
||||
break;
|
||||
case FOURCC_288:
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"Audio: 28_8\n");
|
||||
sh->wf->nBlockAlign = ra_priv->coded_framesize;
|
||||
ra_priv->audio_buf = calloc(ra_priv->sub_packet_h, ra_priv->frame_size);
|
||||
break;
|
||||
case FOURCC_DNET:
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"Audio: DNET -> AC3\n");
|
||||
break;
|
||||
case FOURCC_SIPR:
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"Audio: SIPR\n");
|
||||
sh->wf->nBlockAlign = ra_priv->coded_framesize;
|
||||
sh->wf->nAvgBytesPerSec = sipr_fl2bps[ra_priv->codec_flavor];
|
||||
ra_priv->audio_buf = calloc(ra_priv->sub_packet_h, ra_priv->frame_size);
|
||||
break;
|
||||
default:
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"Audio: Unknown (%d)\n", sh->format);
|
||||
}
|
||||
|
||||
print_wave_header(sh->wf, MSGL_V);
|
||||
|
||||
/* disable seeking */
|
||||
demuxer->seekable = 0;
|
||||
|
||||
if(!ds_fill_buffer(demuxer->audio))
|
||||
mp_msg(MSGT_DEMUXER,MSGL_INFO,"[RealAudio] No data.\n");
|
||||
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void demux_close_ra(demuxer_t *demuxer)
|
||||
{
|
||||
ra_priv_t* ra_priv = demuxer->priv;
|
||||
|
||||
if (ra_priv) {
|
||||
free(ra_priv->audio_buf);
|
||||
free(ra_priv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
/* please upload RV10 samples WITH INDEX CHUNK */
|
||||
int demux_seek_ra(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags)
|
||||
{
|
||||
real_priv_t *priv = demuxer->priv;
|
||||
demux_stream_t *d_audio = demuxer->audio;
|
||||
sh_audio_t *sh_audio = d_audio->sh;
|
||||
int aid = d_audio->id;
|
||||
int next_offset = 0;
|
||||
int rel_seek_frames = 0;
|
||||
int streams = 0;
|
||||
|
||||
return stream_seek(demuxer->stream, next_offset);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_realaudio = {
|
||||
"Realaudio demuxer",
|
||||
"realaudio",
|
||||
"REALAUDIO",
|
||||
"Roberto Togni",
|
||||
"handles old audio only .ra files",
|
||||
DEMUXER_TYPE_REALAUDIO,
|
||||
1, // safe autodetect
|
||||
ra_check_file,
|
||||
demux_ra_fill_buffer,
|
||||
demux_open_ra,
|
||||
demux_close_ra,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
@ -1,769 +0,0 @@
|
||||
/*
|
||||
* VIVO file parser
|
||||
* copyright (c) 2001 A'rpi
|
||||
* VIVO text header parser and audio support by alex
|
||||
*
|
||||
* This file is part of MPlayer.
|
||||
*
|
||||
* MPlayer is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* MPlayer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h> /* strtok */
|
||||
|
||||
#include "config.h"
|
||||
#include "mp_msg.h"
|
||||
|
||||
#include "stream/stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
/* parameters ! */
|
||||
int vivo_param_version = -1;
|
||||
char *vivo_param_acodec = NULL;
|
||||
int vivo_param_abitrate = -1;
|
||||
int vivo_param_samplerate = -1;
|
||||
int vivo_param_bytesperblock = -1;
|
||||
int vivo_param_width = -1;
|
||||
int vivo_param_height = -1;
|
||||
int vivo_param_vformat = -1;
|
||||
|
||||
/* VIVO audio standards from vivog723.acm:
|
||||
|
||||
G.723:
|
||||
FormatTag = 0x111
|
||||
Channels = 1 - mono
|
||||
SamplesPerSec = 8000 - 8khz
|
||||
AvgBytesPerSec = 800
|
||||
BlockAlign (bytes per block) = 24
|
||||
BitsPerSample = 8
|
||||
|
||||
Siren:
|
||||
FormatTag = 0x112
|
||||
Channels = 1 - mono
|
||||
SamplesPerSec = 16000 - 16khz
|
||||
AvgBytesPerSec = 2000
|
||||
BlockAlign (bytes per block) = 40
|
||||
BitsPerSample = 8
|
||||
*/
|
||||
|
||||
//enum { VIVO_AUDIO_G723, VIVO_AUDIO_SIREN };
|
||||
|
||||
#define VIVO_AUDIO_G723 1
|
||||
#define VIVO_AUDIO_SIREN 2
|
||||
|
||||
typedef struct {
|
||||
/* generic */
|
||||
char version;
|
||||
int supported;
|
||||
/* info */
|
||||
char *title;
|
||||
char *author;
|
||||
char *copyright;
|
||||
char *producer;
|
||||
/* video */
|
||||
float fps;
|
||||
int width;
|
||||
int height;
|
||||
int disp_width;
|
||||
int disp_height;
|
||||
/* audio */
|
||||
int audio_codec;
|
||||
int audio_bitrate;
|
||||
int audio_samplerate;
|
||||
int audio_bytesperblock;
|
||||
} vivo_priv_t;
|
||||
|
||||
/* parse all possible extra headers */
|
||||
/* (audio headers are separate - mostly with recordtype=3 or 4) */
|
||||
#define TEXTPARSE_ALL 1
|
||||
|
||||
static void vivo_parse_text_header(demuxer_t *demux, int header_len)
|
||||
{
|
||||
vivo_priv_t* priv = demux->priv;
|
||||
char *buf;
|
||||
int i;
|
||||
char *token;
|
||||
char *opt, *param;
|
||||
int parser_in_audio_block = 0;
|
||||
|
||||
if (!demux->priv)
|
||||
{
|
||||
priv = malloc(sizeof(vivo_priv_t));
|
||||
memset(priv, 0, sizeof(vivo_priv_t));
|
||||
demux->priv = priv;
|
||||
priv->supported = 0;
|
||||
}
|
||||
|
||||
buf = malloc(header_len);
|
||||
opt = malloc(header_len);
|
||||
param = malloc(header_len);
|
||||
stream_read(demux->stream, buf, header_len);
|
||||
i=0;
|
||||
while(i<header_len && buf[i]==0x0D && buf[i+1]==0x0A) i+=2; // skip empty lines
|
||||
|
||||
token = strtok(buf, (char *)&("\x0d\x0a"));
|
||||
while (token && (header_len>2))
|
||||
{
|
||||
header_len -= strlen(token)+2;
|
||||
if (sscanf(token, "%[^:]:%[^\n]", opt, param) != 2)
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "viv_text_header_parser: bad line: '%s' at ~%#"PRIx64"\n",
|
||||
token, (int64_t)stream_tell(demux->stream));
|
||||
break;
|
||||
}
|
||||
mp_dbg(MSGT_DEMUX, MSGL_DBG3, "token: '%s' (%zd bytes/%d bytes left)\n",
|
||||
token, strlen(token), header_len);
|
||||
mp_dbg(MSGT_DEMUX, MSGL_DBG3, "token => o: '%s', p: '%s'\n",
|
||||
opt, param);
|
||||
|
||||
/* checking versions: only v1 or v2 is suitable (or known?:) */
|
||||
if (!strcmp(opt, "Version"))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2, "Version: %s\n", param);
|
||||
if (!strncmp(param, "Vivo/1", 6) || !strncmp(param, "Vivo/2", 6))
|
||||
{
|
||||
priv->supported = 1;
|
||||
/* save major version for fourcc */
|
||||
priv->version = param[5];
|
||||
}
|
||||
}
|
||||
|
||||
/* video specific */
|
||||
if (!strcmp(opt, "FPS"))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2, "FPS: %f\n", atof(param));
|
||||
priv->fps = atof(param);
|
||||
}
|
||||
if (!strcmp(opt, "Width"))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2, "Width: %d\n", atoi(param));
|
||||
priv->width = atoi(param);
|
||||
}
|
||||
if (!strcmp(opt, "Height"))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2, "Height: %d\n", atoi(param));
|
||||
priv->height = atoi(param);
|
||||
}
|
||||
if (!strcmp(opt, "DisplayWidth"))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2, "Display Width: %d\n", atoi(param));
|
||||
priv->disp_width = atoi(param);
|
||||
}
|
||||
if (!strcmp(opt, "DisplayHeight"))
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_DBG2, "Display Height: %d\n", atoi(param));
|
||||
priv->disp_height = atoi(param);
|
||||
}
|
||||
|
||||
/* audio specific */
|
||||
if (!strcmp(opt, "RecordType"))
|
||||
{
|
||||
/* no audio recordblock by Vivo/1.00, 3 and 4 by Vivo/2.00 */
|
||||
if ((atoi(param) == 3) || (atoi(param) == 4))
|
||||
parser_in_audio_block = 1;
|
||||
else
|
||||
parser_in_audio_block = 0;
|
||||
}
|
||||
if (!strcmp(opt, "NominalBitrate"))
|
||||
{
|
||||
priv->audio_bitrate = atoi(param);
|
||||
if (priv->audio_bitrate == 2000)
|
||||
priv->audio_codec = VIVO_AUDIO_SIREN;
|
||||
if (priv->audio_bitrate == 800)
|
||||
priv->audio_codec = VIVO_AUDIO_G723;
|
||||
}
|
||||
if (!strcmp(opt, "SamplingFrequency"))
|
||||
{
|
||||
priv->audio_samplerate = atoi(param);
|
||||
if (priv->audio_samplerate == 16000)
|
||||
priv->audio_codec = VIVO_AUDIO_SIREN;
|
||||
if (priv->audio_samplerate == 8000)
|
||||
priv->audio_codec = VIVO_AUDIO_G723;
|
||||
}
|
||||
if (!strcmp(opt, "Length") && (parser_in_audio_block == 1))
|
||||
{
|
||||
priv->audio_bytesperblock = atoi(param); /* 24 or 40 kbps */
|
||||
if (priv->audio_bytesperblock == 40)
|
||||
priv->audio_codec = VIVO_AUDIO_SIREN;
|
||||
if (priv->audio_bytesperblock == 24)
|
||||
priv->audio_codec = VIVO_AUDIO_G723;
|
||||
}
|
||||
|
||||
/* only for displaying some informations about movie*/
|
||||
if (!strcmp(opt, "Title"))
|
||||
{
|
||||
demux_info_add(demux, "title", param);
|
||||
priv->title = strdup(param);
|
||||
}
|
||||
if (!strcmp(opt, "Author"))
|
||||
{
|
||||
demux_info_add(demux, "author", param);
|
||||
priv->author = strdup(param);
|
||||
}
|
||||
if (!strcmp(opt, "Copyright"))
|
||||
{
|
||||
demux_info_add(demux, "copyright", param);
|
||||
priv->copyright = strdup(param);
|
||||
}
|
||||
if (!strcmp(opt, "Producer"))
|
||||
{
|
||||
demux_info_add(demux, "encoder", param);
|
||||
priv->producer = strdup(param);
|
||||
}
|
||||
|
||||
/* get next token */
|
||||
token = strtok(NULL, (char *)&("\x0d\x0a"));
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(opt);
|
||||
free(param);
|
||||
}
|
||||
|
||||
static int vivo_check_file(demuxer_t* demuxer){
|
||||
int i=0;
|
||||
int len;
|
||||
int c;
|
||||
unsigned char buf[2048+256];
|
||||
vivo_priv_t* priv;
|
||||
int orig_pos = stream_tell(demuxer->stream);
|
||||
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"Checking for VIVO\n");
|
||||
|
||||
c=stream_read_char(demuxer->stream);
|
||||
if(c==-256) return 0;
|
||||
len=0;
|
||||
while((c=stream_read_char(demuxer->stream))>=0x80){
|
||||
len+=0x80*(c-0x80);
|
||||
if(len>1024) return 0;
|
||||
}
|
||||
len+=c;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"header block 1 size: %d\n",len);
|
||||
//stream_skip(demuxer->stream,len);
|
||||
|
||||
priv=malloc(sizeof(vivo_priv_t));
|
||||
memset(priv,0,sizeof(vivo_priv_t));
|
||||
demuxer->priv=priv;
|
||||
|
||||
#if 0
|
||||
vivo_parse_text_header(demuxer, len);
|
||||
if (priv->supported == 0)
|
||||
return 0;
|
||||
#else
|
||||
/* this is enought for check (for now) */
|
||||
stream_read(demuxer->stream,buf,len);
|
||||
buf[len]=0;
|
||||
// printf("VIVO header: '%s'\n",buf);
|
||||
|
||||
// parse header:
|
||||
i=0;
|
||||
while(i<len && buf[i]==0x0D && buf[i+1]==0x0A) i+=2; // skip empty lines
|
||||
if(strncmp(buf+i,"Version:Vivo/",13)) return 0; // bad version/type!
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
c=stream_read_char(demuxer->stream);
|
||||
if(c) return 0;
|
||||
len2=0;
|
||||
while((c=stream_read_char(demuxer->stream))>=0x80){
|
||||
len2+=0x80*(c-0x80);
|
||||
if(len+len2>2048) return 0;
|
||||
}
|
||||
len2+=c;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"header block 2 size: %d\n",len2);
|
||||
stream_skip(demuxer->stream,len2);
|
||||
// stream_read(demuxer->stream,buf+len,len2);
|
||||
#endif
|
||||
|
||||
// c=stream_read_char(demuxer->stream);
|
||||
// printf("first packet: %02X\n",c);
|
||||
|
||||
stream_seek(demuxer->stream, orig_pos);
|
||||
|
||||
return DEMUXER_TYPE_VIVO;
|
||||
}
|
||||
|
||||
static int audio_pos=0;
|
||||
static int audio_rate=0;
|
||||
|
||||
// return value:
|
||||
// 0 = EOF or no stream found
|
||||
// 1 = successfully read a packet
|
||||
static int demux_vivo_fill_buffer(demuxer_t *demux, demux_stream_t *dsds){
|
||||
demux_stream_t *ds=NULL;
|
||||
int c;
|
||||
int len=0;
|
||||
int seq;
|
||||
int prefix=0;
|
||||
demux->filepos=stream_tell(demux->stream);
|
||||
|
||||
c=stream_read_char(demux->stream);
|
||||
if (c == -256) /* EOF */
|
||||
return 0;
|
||||
// printf("c=%x,%02X\n",c,c&0xf0);
|
||||
if (c == 0x82)
|
||||
{
|
||||
/* ok, this works, but pts calculating from header is required! */
|
||||
/* FIXME: "Calculate PTS from picture header!" */
|
||||
prefix = 1;
|
||||
c = stream_read_char(demux->stream);
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "packet 0x82(pos=%u) chunk=%x\n",
|
||||
(int)stream_tell(demux->stream), c);
|
||||
}
|
||||
switch(c&0xF0){
|
||||
case 0x00: // header - skip it!
|
||||
{
|
||||
len=stream_read_char(demux->stream);
|
||||
if(len>=0x80) len=0x80*(len-0x80)+stream_read_char(demux->stream);
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "vivo extra header: %d bytes\n",len);
|
||||
#ifdef TEXTPARSE_ALL
|
||||
{
|
||||
int pos;
|
||||
/* also try to parse all headers */
|
||||
pos = stream_tell(demux->stream);
|
||||
vivo_parse_text_header(demux, len);
|
||||
stream_seek(demux->stream, pos);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 0x10: // video packet
|
||||
if (prefix == 1)
|
||||
len = stream_read_char(demux->stream);
|
||||
else
|
||||
len=128;
|
||||
ds=demux->video;
|
||||
break;
|
||||
case 0x20: // video packet
|
||||
len=stream_read_char(demux->stream);
|
||||
ds=demux->video;
|
||||
break;
|
||||
case 0x30: // audio packet
|
||||
if (prefix == 1)
|
||||
len = stream_read_char(demux->stream);
|
||||
else
|
||||
len=40; /* 40kbps */
|
||||
ds=demux->audio;
|
||||
audio_pos+=len;
|
||||
break;
|
||||
case 0x40: // audio packet
|
||||
if (prefix == 1)
|
||||
len = stream_read_char(demux->stream);
|
||||
else
|
||||
len=24; /* 24kbps */
|
||||
ds=demux->audio;
|
||||
audio_pos+=len;
|
||||
break;
|
||||
default:
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"VIVO - unknown ID found: %02X at pos %"PRIu64" contact author!\n",
|
||||
c, (int64_t)stream_tell(demux->stream));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// printf("chunk=%x, len=%d\n", c, len);
|
||||
|
||||
if(!ds || ds->id<-1){
|
||||
if(len) stream_skip(demux->stream,len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
seq=c&0x0F;
|
||||
|
||||
if(ds->asf_packet){
|
||||
if(ds->asf_seq!=seq){
|
||||
// closed segment, finalize packet:
|
||||
ds_add_packet(ds,ds->asf_packet);
|
||||
ds->asf_packet=NULL;
|
||||
// printf("packet!\n");
|
||||
} else {
|
||||
// append data to it!
|
||||
demux_packet_t* dp=ds->asf_packet;
|
||||
if(dp->len + len + MP_INPUT_BUFFER_PADDING_SIZE < 0)
|
||||
return 0;
|
||||
dp->buffer=realloc(dp->buffer,dp->len+len+MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
memset(dp->buffer+dp->len+len, 0, MP_INPUT_BUFFER_PADDING_SIZE);
|
||||
//memcpy(dp->buffer+dp->len,data,len);
|
||||
stream_read(demux->stream,dp->buffer+dp->len,len);
|
||||
mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len);
|
||||
dp->len+=len;
|
||||
// we are ready now.
|
||||
if((c&0xF0)==0x20) --ds->asf_seq; // hack!
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// create new packet:
|
||||
{ demux_packet_t* dp;
|
||||
dp=new_demux_packet(len);
|
||||
//memcpy(dp->buffer,data,len);
|
||||
stream_read(demux->stream,dp->buffer,len);
|
||||
dp->pts=audio_rate?((float)audio_pos/(float)audio_rate):0;
|
||||
// dp->flags=keyframe;
|
||||
// if(ds==demux->video) printf("ASF time: %8d dur: %5d \n",time,dur);
|
||||
dp->pos=demux->filepos;
|
||||
ds->asf_packet=dp;
|
||||
ds->asf_seq=seq;
|
||||
// we are ready now.
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static const short h263_format[8][2] = {
|
||||
{ 0, 0 },
|
||||
{ 128, 96 },
|
||||
{ 176, 144 },
|
||||
{ 352, 288 },
|
||||
{ 704, 576 },
|
||||
{ 1408, 1152 },
|
||||
{ 320, 240 } // ??????? or 240x180 (found in vivo2) ?
|
||||
};
|
||||
|
||||
static unsigned char* buffer;
|
||||
static int bufptr=0;
|
||||
static int bitcnt=0;
|
||||
static unsigned char buf=0;
|
||||
static int format, width, height;
|
||||
|
||||
static unsigned int x_get_bits(int n){
|
||||
unsigned int x=0;
|
||||
while(n-->0){
|
||||
if(!bitcnt){
|
||||
// fill buff
|
||||
buf=buffer[bufptr++];
|
||||
bitcnt=8;
|
||||
}
|
||||
//x=(x<<1)|(buf&1);buf>>=1;
|
||||
x=(x<<1)|(buf>>7);buf<<=1;
|
||||
--bitcnt;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
#define get_bits(xxx,n) x_get_bits(n)
|
||||
#define get_bits1(xxx) x_get_bits(1)
|
||||
#define skip_bits(xxx,n) x_get_bits(n)
|
||||
#define skip_bits1(xxx) x_get_bits(1)
|
||||
|
||||
/* most is hardcoded. should extend to handle all h263 streams */
|
||||
static int h263_decode_picture_header(unsigned char *b_ptr)
|
||||
{
|
||||
// int i;
|
||||
|
||||
// for(i=0;i<16;i++) printf(" %02X",b_ptr[i]); printf("\n");
|
||||
|
||||
buffer=b_ptr;
|
||||
bufptr=bitcnt=buf=0;
|
||||
|
||||
/* picture header */
|
||||
if (get_bits(&s->gb, 22) != 0x20){
|
||||
mp_msg(MSGT_DEMUX, MSGL_FATAL, "bad picture header\n");
|
||||
return -1;
|
||||
}
|
||||
skip_bits(&s->gb, 8); /* picture timestamp */
|
||||
|
||||
if (get_bits1(&s->gb) != 1){
|
||||
mp_msg(MSGT_DEMUX, MSGL_FATAL, "bad marker\n");
|
||||
return -1; /* marker */
|
||||
}
|
||||
if (get_bits1(&s->gb) != 0){
|
||||
mp_msg(MSGT_DEMUX, MSGL_FATAL, "bad h263 id\n");
|
||||
return -1; /* h263 id */
|
||||
}
|
||||
skip_bits1(&s->gb); /* split screen off */
|
||||
skip_bits1(&s->gb); /* camera off */
|
||||
skip_bits1(&s->gb); /* freeze picture release off */
|
||||
|
||||
format = get_bits(&s->gb, 3);
|
||||
|
||||
if (format != 7) {
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "h263_plus = 0 format = %d\n", format);
|
||||
/* H.263v1 */
|
||||
width = h263_format[format][0];
|
||||
height = h263_format[format][1];
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "%d x %d\n", width, height);
|
||||
// if (!width) return -1;
|
||||
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "pict_type=%d\n", get_bits1(&s->gb));
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "unrestricted_mv=%d\n", get_bits1(&s->gb));
|
||||
#if 1
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "SAC: %d\n", get_bits1(&s->gb));
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "advanced prediction mode: %d\n", get_bits1(&s->gb));
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "PB frame: %d\n", get_bits1(&s->gb));
|
||||
#else
|
||||
if (get_bits1(&s->gb) != 0)
|
||||
return -1; /* SAC: off */
|
||||
if (get_bits1(&s->gb) != 0)
|
||||
return -1; /* advanced prediction mode: off */
|
||||
if (get_bits1(&s->gb) != 0)
|
||||
return -1; /* not PB frame */
|
||||
#endif
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "qscale=%d\n", get_bits(&s->gb, 5));
|
||||
skip_bits1(&s->gb); /* Continuous Presence Multipoint mode: off */
|
||||
} else {
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "h263_plus = 1\n");
|
||||
/* H.263v2 */
|
||||
if (get_bits(&s->gb, 3) != 1){
|
||||
mp_msg(MSGT_DEMUX, MSGL_FATAL, "H.263v2 A error\n");
|
||||
return -1;
|
||||
}
|
||||
if (get_bits(&s->gb, 3) != 6){ /* custom source format */
|
||||
mp_msg(MSGT_DEMUX, MSGL_FATAL, "custom source format\n");
|
||||
return -1;
|
||||
}
|
||||
skip_bits(&s->gb, 12);
|
||||
skip_bits(&s->gb, 3);
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "pict_type=%d\n", get_bits(&s->gb, 3) + 1);
|
||||
// if (s->pict_type != I_TYPE &&
|
||||
// s->pict_type != P_TYPE)
|
||||
// return -1;
|
||||
skip_bits(&s->gb, 7);
|
||||
skip_bits(&s->gb, 4); /* aspect ratio */
|
||||
width = (get_bits(&s->gb, 9) + 1) * 4;
|
||||
skip_bits1(&s->gb);
|
||||
height = get_bits(&s->gb, 9) * 4;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "%d x %d\n", width, height);
|
||||
//if (height == 0)
|
||||
// return -1;
|
||||
mp_msg(MSGT_DEMUX, MSGL_V, "qscale=%d\n", get_bits(&s->gb, 5));
|
||||
}
|
||||
|
||||
/* PEI */
|
||||
while (get_bits1(&s->gb) != 0) {
|
||||
skip_bits(&s->gb, 8);
|
||||
}
|
||||
// s->f_code = 1;
|
||||
// s->width = width;
|
||||
// s->height = height;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static demuxer_t* demux_open_vivo(demuxer_t* demuxer){
|
||||
vivo_priv_t* priv=demuxer->priv;
|
||||
|
||||
if(!ds_fill_buffer(demuxer->video)){
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "VIVO: %s",
|
||||
mp_gtext("Missing video stream!? Contact the author, it may be a bug :(\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
audio_pos=0;
|
||||
|
||||
h263_decode_picture_header(demuxer->video->buffer);
|
||||
|
||||
if (vivo_param_version != -1)
|
||||
priv->version = '0' + vivo_param_version;
|
||||
|
||||
{ sh_video_t* sh=new_sh_video(demuxer,0);
|
||||
|
||||
/* viv1, viv2 (for better codecs.conf) */
|
||||
sh->format = mmioFOURCC('v', 'i', 'v', priv->version);
|
||||
if(!sh->fps)
|
||||
{
|
||||
if (priv->fps)
|
||||
sh->fps=priv->fps;
|
||||
else
|
||||
sh->fps=15.0f;
|
||||
}
|
||||
sh->frametime=1.0f/sh->fps;
|
||||
|
||||
/* XXX: FIXME: can't scale image. */
|
||||
/* hotfix to disable: */
|
||||
priv->disp_width = priv->width;
|
||||
priv->disp_height = priv->height;
|
||||
|
||||
if (vivo_param_width != -1)
|
||||
priv->disp_width = priv->width = vivo_param_width;
|
||||
|
||||
if (vivo_param_height != -1)
|
||||
priv->disp_height = priv->height = vivo_param_height;
|
||||
|
||||
if (vivo_param_vformat != -1)
|
||||
{
|
||||
priv->disp_width = priv->width = h263_format[vivo_param_vformat][0];
|
||||
priv->disp_height = priv->height = h263_format[vivo_param_vformat][1];
|
||||
}
|
||||
|
||||
if (priv->disp_width)
|
||||
sh->disp_w = priv->disp_width;
|
||||
else
|
||||
sh->disp_w = width;
|
||||
if (priv->disp_height)
|
||||
sh->disp_h = priv->disp_height;
|
||||
else
|
||||
sh->disp_h = height;
|
||||
|
||||
// emulate BITMAPINFOHEADER:
|
||||
sh->bih=calloc(1, sizeof(*sh->bih));
|
||||
sh->bih->biSize=40;
|
||||
if (priv->width)
|
||||
sh->bih->biWidth = priv->width;
|
||||
else
|
||||
sh->bih->biWidth = width;
|
||||
if (priv->height)
|
||||
sh->bih->biHeight = priv->height;
|
||||
else
|
||||
sh->bih->biHeight = height;
|
||||
sh->bih->biPlanes=1;
|
||||
sh->bih->biBitCount=24;
|
||||
sh->bih->biCompression=sh->format;
|
||||
sh->bih->biSizeImage=sh->bih->biWidth*sh->bih->biHeight*3;
|
||||
|
||||
/* insert as stream */
|
||||
demuxer->video->sh=sh;
|
||||
sh->ds=demuxer->video;
|
||||
demuxer->video->id=0;
|
||||
|
||||
/* disable seeking */
|
||||
demuxer->seekable = 0;
|
||||
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"VIVO Video stream %d size: display: %dx%d, codec: %ux%u\n",
|
||||
demuxer->video->id, sh->disp_w, sh->disp_h, sh->bih->biWidth,
|
||||
sh->bih->biHeight);
|
||||
}
|
||||
|
||||
/* AUDIO init */
|
||||
if (demuxer->audio->id >= -1){
|
||||
if(!ds_fill_buffer(demuxer->audio)){
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "VIVO: %s",
|
||||
mp_gtext("No audio stream found -> no sound.\n"));
|
||||
} else
|
||||
{ sh_audio_t* sh=new_sh_audio(demuxer,1);
|
||||
|
||||
/* Select audio codec */
|
||||
if (priv->audio_codec == 0)
|
||||
{
|
||||
if (priv->version == '2')
|
||||
priv->audio_codec = VIVO_AUDIO_SIREN;
|
||||
else
|
||||
priv->audio_codec = VIVO_AUDIO_G723;
|
||||
}
|
||||
if (vivo_param_acodec != NULL)
|
||||
{
|
||||
if (!strcasecmp(vivo_param_acodec, "g723"))
|
||||
priv->audio_codec = VIVO_AUDIO_G723;
|
||||
if (!strcasecmp(vivo_param_acodec, "siren"))
|
||||
priv->audio_codec = VIVO_AUDIO_SIREN;
|
||||
}
|
||||
|
||||
if (priv->audio_codec == VIVO_AUDIO_G723)
|
||||
sh->format = 0x111;
|
||||
else if (priv->audio_codec == VIVO_AUDIO_SIREN)
|
||||
sh->format = 0x112;
|
||||
else
|
||||
{
|
||||
mp_msg(MSGT_DEMUX, MSGL_ERR, "VIVO: Not support audio codec (%d)\n",
|
||||
priv->audio_codec);
|
||||
free_sh_audio(demuxer, 1);
|
||||
goto nosound;
|
||||
}
|
||||
|
||||
// Emulate WAVEFORMATEX struct:
|
||||
sh->wf=calloc(1, sizeof(*sh->wf));
|
||||
sh->wf->wFormatTag=sh->format;
|
||||
sh->wf->nChannels=1; /* 1 channels for both Siren and G.723 */
|
||||
|
||||
/* Set bits per sample */
|
||||
if (priv->audio_codec == VIVO_AUDIO_SIREN)
|
||||
sh->wf->wBitsPerSample = 16;
|
||||
else
|
||||
if (priv->audio_codec == VIVO_AUDIO_G723)
|
||||
sh->wf->wBitsPerSample = 8;
|
||||
|
||||
/* Set sampling rate */
|
||||
if (priv->audio_samplerate) /* got from header */
|
||||
sh->wf->nSamplesPerSec = priv->audio_samplerate;
|
||||
else
|
||||
{
|
||||
if (priv->audio_codec == VIVO_AUDIO_SIREN)
|
||||
sh->wf->nSamplesPerSec = 16000;
|
||||
if (priv->audio_codec == VIVO_AUDIO_G723)
|
||||
sh->wf->nSamplesPerSec = 8000;
|
||||
}
|
||||
if (vivo_param_samplerate != -1)
|
||||
sh->wf->nSamplesPerSec = vivo_param_samplerate;
|
||||
|
||||
/* Set audio bitrate */
|
||||
if (priv->audio_bitrate) /* got from header */
|
||||
sh->wf->nAvgBytesPerSec = priv->audio_bitrate;
|
||||
else
|
||||
{
|
||||
if (priv->audio_codec == VIVO_AUDIO_SIREN)
|
||||
sh->wf->nAvgBytesPerSec = 2000;
|
||||
if (priv->audio_codec == VIVO_AUDIO_G723)
|
||||
sh->wf->nAvgBytesPerSec = 800;
|
||||
}
|
||||
if (vivo_param_abitrate != -1)
|
||||
sh->wf->nAvgBytesPerSec = vivo_param_abitrate;
|
||||
audio_rate=sh->wf->nAvgBytesPerSec;
|
||||
|
||||
if (!priv->audio_bytesperblock)
|
||||
{
|
||||
if (priv->audio_codec == VIVO_AUDIO_SIREN)
|
||||
sh->wf->nBlockAlign = 40;
|
||||
if (priv->audio_codec == VIVO_AUDIO_G723)
|
||||
sh->wf->nBlockAlign = 24;
|
||||
}
|
||||
else
|
||||
sh->wf->nBlockAlign = priv->audio_bytesperblock;
|
||||
if (vivo_param_bytesperblock != -1)
|
||||
sh->wf->nBlockAlign = vivo_param_bytesperblock;
|
||||
|
||||
/*sound_ok:*/
|
||||
/* insert as stream */
|
||||
demuxer->audio->sh=sh;
|
||||
sh->ds=demuxer->audio;
|
||||
demuxer->audio->id=1;
|
||||
nosound:
|
||||
return demuxer;
|
||||
}
|
||||
}
|
||||
return demuxer;
|
||||
}
|
||||
|
||||
static void demux_close_vivo(demuxer_t *demuxer)
|
||||
{
|
||||
vivo_priv_t* priv=demuxer->priv;
|
||||
|
||||
if (priv) {
|
||||
free(priv->title);
|
||||
free(priv->author);
|
||||
free(priv->copyright);
|
||||
free(priv->producer);
|
||||
free(priv);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const demuxer_desc_t demuxer_desc_vivo = {
|
||||
"Vivo demuxer",
|
||||
"vivo",
|
||||
"VIVO",
|
||||
"A'rpi, Alex Beregszasi",
|
||||
"",
|
||||
DEMUXER_TYPE_VIVO,
|
||||
0, // unsafe autodetect
|
||||
vivo_check_file,
|
||||
demux_vivo_fill_buffer,
|
||||
demux_open_vivo,
|
||||
demux_close_vivo,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
@ -58,14 +58,9 @@ extern const demuxer_desc_t demuxer_desc_tv;
|
||||
extern const demuxer_desc_t demuxer_desc_mf;
|
||||
extern const demuxer_desc_t demuxer_desc_avi;
|
||||
extern const demuxer_desc_t demuxer_desc_asf;
|
||||
extern const demuxer_desc_t demuxer_desc_real;
|
||||
extern const demuxer_desc_t demuxer_desc_matroska;
|
||||
extern const demuxer_desc_t demuxer_desc_realaudio;
|
||||
extern const demuxer_desc_t demuxer_desc_vivo;
|
||||
extern const demuxer_desc_t demuxer_desc_gif;
|
||||
extern const demuxer_desc_t demuxer_desc_avs;
|
||||
extern const demuxer_desc_t demuxer_desc_rawdv;
|
||||
extern const demuxer_desc_t demuxer_desc_audio;
|
||||
extern const demuxer_desc_t demuxer_desc_rtp;
|
||||
extern const demuxer_desc_t demuxer_desc_rtp_nemesi;
|
||||
extern const demuxer_desc_t demuxer_desc_lavf;
|
||||
@ -89,14 +84,9 @@ const demuxer_desc_t *const demuxer_list[] = {
|
||||
&demuxer_desc_avi,
|
||||
&demuxer_desc_asf,
|
||||
&demuxer_desc_matroska,
|
||||
&demuxer_desc_realaudio,
|
||||
#ifdef CONFIG_GIF
|
||||
&demuxer_desc_gif,
|
||||
#endif
|
||||
#ifdef CONFIG_WIN32DLL
|
||||
&demuxer_desc_avs,
|
||||
#endif
|
||||
&demuxer_desc_audio,
|
||||
#ifdef CONFIG_LIVE555
|
||||
&demuxer_desc_rtp,
|
||||
#endif
|
||||
|
@ -49,12 +49,9 @@ enum demuxer_type {
|
||||
DEMUXER_TYPE_AVI_NI,
|
||||
DEMUXER_TYPE_AVI_NINI,
|
||||
DEMUXER_TYPE_ASF,
|
||||
DEMUXER_TYPE_VIVO,
|
||||
DEMUXER_TYPE_TV,
|
||||
DEMUXER_TYPE_REAL,
|
||||
DEMUXER_TYPE_Y4M,
|
||||
DEMUXER_TYPE_MF,
|
||||
DEMUXER_TYPE_AUDIO,
|
||||
DEMUXER_TYPE_RAWAUDIO,
|
||||
DEMUXER_TYPE_RTP,
|
||||
DEMUXER_TYPE_RAWDV,
|
||||
@ -62,7 +59,6 @@ enum demuxer_type {
|
||||
DEMUXER_TYPE_GIF,
|
||||
DEMUXER_TYPE_MPEG_TS,
|
||||
DEMUXER_TYPE_MATROSKA,
|
||||
DEMUXER_TYPE_REALAUDIO,
|
||||
DEMUXER_TYPE_LAVF,
|
||||
DEMUXER_TYPE_NSV,
|
||||
DEMUXER_TYPE_AVS,
|
||||
|
@ -45,16 +45,14 @@ static struct {
|
||||
{ "asf", DEMUXER_TYPE_ASF },
|
||||
{ "wmv", DEMUXER_TYPE_ASF },
|
||||
{ "wma", DEMUXER_TYPE_ASF },
|
||||
{ "viv", DEMUXER_TYPE_VIVO },
|
||||
{ "vivo", DEMUXER_TYPE_VIVO },
|
||||
{ "rm", DEMUXER_TYPE_REAL },
|
||||
{ "rmvb", DEMUXER_TYPE_REAL },
|
||||
{ "ra", DEMUXER_TYPE_REAL },
|
||||
{ "rm", DEMUXER_TYPE_LAVF },
|
||||
{ "rmvb", DEMUXER_TYPE_LAVF },
|
||||
{ "ra", DEMUXER_TYPE_LAVF },
|
||||
{ "y4m", DEMUXER_TYPE_Y4M },
|
||||
{ "mp3", DEMUXER_TYPE_AUDIO },
|
||||
{ "wav", DEMUXER_TYPE_AUDIO },
|
||||
{ "flac", DEMUXER_TYPE_AUDIO },
|
||||
{ "fla", DEMUXER_TYPE_AUDIO },
|
||||
{ "mp3", DEMUXER_TYPE_LAVF },
|
||||
{ "wav", DEMUXER_TYPE_LAVF },
|
||||
{ "flac", DEMUXER_TYPE_LAVF },
|
||||
{ "fla", DEMUXER_TYPE_LAVF },
|
||||
{ "ogg", DEMUXER_TYPE_LAVF },
|
||||
{ "ogm", DEMUXER_TYPE_LAVF },
|
||||
// { "pls", DEMUXER_TYPE_PLAYLIST },
|
||||
|
@ -1,293 +0,0 @@
|
||||
/***********************************
|
||||
* Copyright (C) 2001 Jason Carter
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
***********************************
|
||||
* FILE: GENRES.H
|
||||
* NAME: ID3EDIT - ID3 tag v 1.1 editor
|
||||
* DESCRIPTION: Genres character array
|
||||
* AUTHOR: Jason Carter
|
||||
***********************************
|
||||
*
|
||||
* Initially modified for use with MPlayer by Diego Biurrun on 2004-08-22
|
||||
* $Id$
|
||||
* detailed changelog at http://svn.mplayerhq.hu/mplayer/trunk/
|
||||
*/
|
||||
|
||||
#ifndef MPLAYER_GENRES_H
|
||||
#define MPLAYER_GENRES_H
|
||||
|
||||
|
||||
const char * const genres[] = {
|
||||
"Blues", /* 0 */
|
||||
"Classic Rock", /* 1 */
|
||||
"Country", /* 2 */
|
||||
"Dance", /* 3 */
|
||||
"Disco", /* 4 */
|
||||
"Funk", /* 5 */
|
||||
"Grunge", /* 6 */
|
||||
"Hip-Hop", /* 7 */
|
||||
"Jazz", /* 8 */
|
||||
"Metal", /* 9 */
|
||||
"New Age", /* 10 */
|
||||
"Oldies", /* 11 */
|
||||
"Other", /* 12 */
|
||||
"Pop", /* 13 */
|
||||
"R&B", /* 14 */
|
||||
"Rap", /* 15 */
|
||||
"Reggae", /* 16 */
|
||||
"Rock", /* 17 */
|
||||
"Techno", /* 18 */
|
||||
"Industrial", /* 19 */
|
||||
"Alternative", /* 20 */
|
||||
"Ska", /* 21 */
|
||||
"Death Metal", /* 22 */
|
||||
"Pranks", /* 23 */
|
||||
"Soundtrack", /* 24 */
|
||||
"Eurotechno", /* 25 */
|
||||
"Ambient", /* 26 */
|
||||
"Trip-Hop", /* 27 */
|
||||
"Vocal", /* 28 */
|
||||
"Jazz+Funk", /* 29 */
|
||||
"Fusion", /* 30 */
|
||||
"Trance", /* 31 */
|
||||
"Classical", /* 32 */
|
||||
"Instrumental", /* 33 */
|
||||
"Acid", /* 34 */
|
||||
"House", /* 35 */
|
||||
"Game", /* 36 */
|
||||
"Sound Clip", /* 37 */
|
||||
"Gospel", /* 38 */
|
||||
"Noise", /* 39 */
|
||||
"Alternative Rock", /* 40 */
|
||||
"Bass", /* 41 */
|
||||
"Soul", /* 42 */
|
||||
"Punk", /* 43 */
|
||||
"Space", /* 44 */
|
||||
"Meditative", /* 45 */
|
||||
"Instrumental Pop", /* 46 */
|
||||
"Instrumental Rock", /* 47 */
|
||||
"Ethnic", /* 48 */
|
||||
"Gothic", /* 49 */
|
||||
"Darkwave", /* 50 */
|
||||
"Techno-Industrial", /* 51 */
|
||||
"Electronic", /* 52 */
|
||||
"Pop-Folk", /* 53 */
|
||||
"Eurodance", /* 54 */
|
||||
"Dream", /* 55 */
|
||||
"Southern Rock", /* 56 */
|
||||
"Comedy", /* 57 */
|
||||
"Cult", /* 58 */
|
||||
"Gangsta", /* 59 */
|
||||
"Top 40", /* 60 */
|
||||
"Christian Rap", /* 61 */
|
||||
"Pop/Funk", /* 62 */
|
||||
"Jungle", /* 63 */
|
||||
"Native American", /* 64 */
|
||||
"Cabaret", /* 65 */
|
||||
"New Wave", /* 66 */
|
||||
"Psychadelic", /* 67 */ /* typo taken from the id3v2spec*/
|
||||
"Rave", /* 68 */
|
||||
"Show Tunes", /* 69 */
|
||||
"Trailer", /* 70 */
|
||||
"Lo-Fi", /* 71 */
|
||||
"Tribal", /* 72 */
|
||||
"Acid Punk", /* 73 */
|
||||
"Acid Jazz", /* 74 */
|
||||
"Polka", /* 75 */
|
||||
"Retro", /* 76 */
|
||||
"Musical", /* 77 */
|
||||
"Rock & Roll", /* 78 */
|
||||
"Hard Rock", /* 79 */
|
||||
"Folk", /* 80 */
|
||||
"Folk/Rock", /* 81 */
|
||||
"National Folk", /* 82 */
|
||||
"Swing", /* 83 */
|
||||
"Fast-Fusion", /* 84 */
|
||||
"Bebop", /* 85 */
|
||||
"Latin", /* 86 */
|
||||
"Revival", /* 87 */
|
||||
"Celtic", /* 88 */
|
||||
"Bluegrass", /* 89 */
|
||||
"Avantgarde", /* 90 */
|
||||
"Gothic Rock", /* 91 */
|
||||
"Progressive Rock", /* 92 */
|
||||
"Psychedelic Rock", /* 93 */
|
||||
"Symphonic Rock", /* 94 */
|
||||
"Slow Rock", /* 95 */
|
||||
"Big Band", /* 96 */
|
||||
"Chorus", /* 97 */
|
||||
"Easy Listening", /* 98 */
|
||||
"Acoustic", /* 99 */
|
||||
"Humour", /* 100 */
|
||||
"Speech", /* 101 */
|
||||
"Chanson", /* 102 */
|
||||
"Opera", /* 103 */
|
||||
"Chamber Music", /* 104 */
|
||||
"Sonata", /* 105 */
|
||||
"Symphony", /* 106 */
|
||||
"Booty Bass", /* 107 */
|
||||
"Primus", /* 108 */
|
||||
"Porn Groove", /* 109 */
|
||||
"Satire", /* 110 */
|
||||
"Slow Jam", /* 111 */
|
||||
"Club", /* 112 */
|
||||
"Tango", /* 113 */
|
||||
"Samba", /* 114 */
|
||||
"Folklore", /* 115 */
|
||||
"Ballad", /* 116 */
|
||||
"Power Ballad", /* 117 */
|
||||
"Rhytmic Soul", /* 118 */
|
||||
"Freestyle", /* 119 */
|
||||
"Duet", /* 120 */
|
||||
"Punk Rock", /* 121 */
|
||||
"Drum Solo", /* 122 */
|
||||
"Acapella", /* 123 */
|
||||
"Euro-House", /* 124 */
|
||||
"Dance Hall", /* 125 */
|
||||
"Goa", /* 126 */
|
||||
"Drum & Bass", /* 127 */
|
||||
"Club-House", /* 128 */
|
||||
"Hardcore", /* 129 */
|
||||
"Terror", /* 130 */
|
||||
"Indie", /* 131 */
|
||||
"BritPop", /* 132 */
|
||||
"Negerpunk", /* 133 */
|
||||
"Polsk Punk", /* 134 */
|
||||
"Beat", /* 135 */
|
||||
"Christian Gangsta Rap", /* 136 */
|
||||
"Heavy Metal", /* 137 */
|
||||
"Black Metal", /* 138 */
|
||||
"Crossover", /* 139 */
|
||||
"Contemporary Christian", /* 140 */
|
||||
"Christian Rock", /* 141 */
|
||||
"Merengue", /* 142 */
|
||||
"Salsa", /* 143 */
|
||||
"Thrash Metal", /* 144 */
|
||||
"Anime", /* 145 */
|
||||
"Jpop", /* 146 */
|
||||
"Synthpop", /* 147 */
|
||||
"Unknown", /* 148 */
|
||||
"Unknown", /* 149 */
|
||||
"Unknown", /* 150 */
|
||||
"Unknown", /* 151 */
|
||||
"Unknown", /* 152 */
|
||||
"Unknown", /* 153 */
|
||||
"Unknown", /* 154 */
|
||||
"Unknown", /* 155 */
|
||||
"Unknown", /* 156 */
|
||||
"Unknown", /* 157 */
|
||||
"Unknown", /* 158 */
|
||||
"Unknown", /* 159 */
|
||||
"Unknown", /* 160 */
|
||||
"Unknown", /* 161 */
|
||||
"Unknown", /* 162 */
|
||||
"Unknown", /* 163 */
|
||||
"Unknown", /* 164 */
|
||||
"Unknown", /* 165 */
|
||||
"Unknown", /* 166 */
|
||||
"Unknown", /* 167 */
|
||||
"Unknown", /* 168 */
|
||||
"Unknown", /* 169 */
|
||||
"Unknown", /* 170 */
|
||||
"Unknown", /* 171 */
|
||||
"Unknown", /* 172 */
|
||||
"Unknown", /* 173 */
|
||||
"Unknown", /* 174 */
|
||||
"Unknown", /* 175 */
|
||||
"Unknown", /* 176 */
|
||||
"Unknown", /* 177 */
|
||||
"Unknown", /* 178 */
|
||||
"Unknown", /* 179 */
|
||||
"Unknown", /* 180 */
|
||||
"Unknown", /* 181 */
|
||||
"Unknown", /* 182 */
|
||||
"Unknown", /* 183 */
|
||||
"Unknown", /* 184 */
|
||||
"Unknown", /* 185 */
|
||||
"Unknown", /* 186 */
|
||||
"Unknown", /* 187 */
|
||||
"Unknown", /* 188 */
|
||||
"Unknown", /* 189 */
|
||||
"Unknown", /* 190 */
|
||||
"Unknown", /* 191 */
|
||||
"Unknown", /* 192 */
|
||||
"Unknown", /* 193 */
|
||||
"Unknown", /* 194 */
|
||||
"Unknown", /* 195 */
|
||||
"Unknown", /* 196 */
|
||||
"Unknown", /* 197 */
|
||||
"Unknown", /* 198 */
|
||||
"Unknown", /* 199 */
|
||||
"Unknown", /* 200 */
|
||||
"Unknown", /* 201 */
|
||||
"Unknown", /* 202 */
|
||||
"Unknown", /* 203 */
|
||||
"Unknown", /* 204 */
|
||||
"Unknown", /* 205 */
|
||||
"Unknown", /* 206 */
|
||||
"Unknown", /* 207 */
|
||||
"Unknown", /* 208 */
|
||||
"Unknown", /* 209 */
|
||||
"Unknown", /* 210 */
|
||||
"Unknown", /* 211 */
|
||||
"Unknown", /* 212 */
|
||||
"Unknown", /* 213 */
|
||||
"Unknown", /* 214 */
|
||||
"Unknown", /* 215 */
|
||||
"Unknown", /* 216 */
|
||||
"Unknown", /* 217 */
|
||||
"Unknown", /* 218 */
|
||||
"Unknown", /* 219 */
|
||||
"Unknown", /* 220 */
|
||||
"Unknown", /* 221 */
|
||||
"Unknown", /* 222 */
|
||||
"Unknown", /* 223 */
|
||||
"Unknown", /* 224 */
|
||||
"Unknown", /* 225 */
|
||||
"Unknown", /* 226 */
|
||||
"Unknown", /* 227 */
|
||||
"Unknown", /* 228 */
|
||||
"Unknown", /* 229 */
|
||||
"Unknown", /* 230 */
|
||||
"Unknown", /* 231 */
|
||||
"Unknown", /* 232 */
|
||||
"Unknown", /* 233 */
|
||||
"Unknown", /* 234 */
|
||||
"Unknown", /* 235 */
|
||||
"Unknown", /* 236 */
|
||||
"Unknown", /* 237 */
|
||||
"Unknown", /* 238 */
|
||||
"Unknown", /* 239 */
|
||||
"Unknown", /* 240 */
|
||||
"Unknown", /* 241 */
|
||||
"Unknown", /* 242 */
|
||||
"Unknown", /* 243 */
|
||||
"Unknown", /* 244 */
|
||||
"Unknown", /* 245 */
|
||||
"Unknown", /* 246 */
|
||||
"Unknown", /* 247 */
|
||||
"Unknown", /* 248 */
|
||||
"Unknown", /* 249 */
|
||||
"Unknown", /* 250 */
|
||||
"Unknown", /* 251 */
|
||||
"Unknown", /* 252 */
|
||||
"Unknown", /* 253 */
|
||||
"Unknown", /* 254 */
|
||||
"Unknown", /* 255 */
|
||||
};
|
||||
|
||||
#endif /* MPLAYER_GENRES_H */
|
@ -86,8 +86,6 @@ int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char**
|
||||
if(d_video->pts>0 && pts1>0 && d_video->pts>pts1)
|
||||
frame_time=d_video->pts-pts1;
|
||||
break;
|
||||
case DEMUXER_TYPE_TV:
|
||||
case DEMUXER_TYPE_VIVO:
|
||||
case DEMUXER_TYPE_ASF: {
|
||||
double next_pts = ds_get_next_pts(d_video);
|
||||
double d= (next_pts != MP_NOPTS_VALUE) ? next_pts - d_video->pts : d_video->pts-pts1;
|
||||
@ -115,14 +113,6 @@ int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char**
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DEMUXER_TYPE_REAL:
|
||||
{
|
||||
double next_pts = ds_get_next_pts(d_video);
|
||||
double d = (next_pts != MP_NOPTS_VALUE) ? next_pts - d_video->pts : d_video->pts - pts1;
|
||||
|
||||
frame_time = (d >= 0 && pts1 > 0) ? d : 0.001;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
@ -771,7 +771,7 @@ static int http_streaming_start(stream_t *stream, int* file_format) {
|
||||
else if ( (field_data = http_get_field(http_hdr, "content-type")) != NULL && (!strcmp(field_data, "audio/aacp") || !strcmp(field_data, "audio/aac")))
|
||||
*file_format = DEMUXER_TYPE_AAC;
|
||||
else
|
||||
*file_format = DEMUXER_TYPE_AUDIO;
|
||||
*file_format = DEMUXER_TYPE_LAVF;
|
||||
res = STREAM_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ int network_ipv4_only_proxy = 0;
|
||||
|
||||
const mime_struct_t mime_type_table[] = {
|
||||
// MP3 streaming, some MP3 streaming server answer with audio/mpeg
|
||||
{ "audio/mpeg", DEMUXER_TYPE_AUDIO },
|
||||
{ "audio/mpeg", DEMUXER_TYPE_LAVF },
|
||||
// ASF
|
||||
{ "audio/x-ms-wax", DEMUXER_TYPE_ASF },
|
||||
{ "audio/x-ms-wma", DEMUXER_TYPE_ASF },
|
||||
|
Loading…
Reference in New Issue
Block a user