mirror of
https://github.com/mpv-player/mpv
synced 2024-12-18 21:06:00 +00:00
Initial ogg demuxer. No seeking, a/v sync is broken. Support avi
with ogg/vorbis audio. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@5134 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
7644b575f9
commit
14316b3379
319
dec_audio.c
319
dec_audio.c
@ -73,13 +73,8 @@ static DS_AudioDecoder* ds_adec=NULL;
|
||||
#include <math.h>
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
// This struct is also defined in demux_ogg.c => common header ?
|
||||
typedef struct ov_struct_st {
|
||||
ogg_sync_state oy; /* sync and verify incoming physical bitstream */
|
||||
ogg_stream_state os; /* take physical pages, weld into a logical
|
||||
stream of packets */
|
||||
ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
|
||||
ogg_packet op; /* one raw packet of data for decode */
|
||||
|
||||
vorbis_info vi; /* struct that stores all the static vorbis bitstream
|
||||
settings */
|
||||
vorbis_comment vc; /* struct that stores all the bitstream user comments */
|
||||
@ -389,6 +384,7 @@ case AFM_VORBIS:
|
||||
driver=0;
|
||||
#else
|
||||
/* OggVorbis audio via libvorbis, compatible with files created by nandub and zorannt codec */
|
||||
// Is there always 1024 samples/frame ? ***** Albeu
|
||||
sh_audio->audio_out_minsize=1024*4; // 1024 samples/frame
|
||||
#endif
|
||||
break;
|
||||
@ -759,124 +755,61 @@ case AFM_MPEG: {
|
||||
}
|
||||
#ifdef HAVE_OGGVORBIS
|
||||
case AFM_VORBIS: {
|
||||
// OggVorbis Audio:
|
||||
#if 0 /* just here for reference - atmos */
|
||||
ogg_sync_state oy; /* sync and verify incoming physical bitstream */
|
||||
ogg_stream_state os; /* take physical pages, weld into a logical
|
||||
stream of packets */
|
||||
ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
|
||||
ogg_packet op; /* one raw packet of data for decode */
|
||||
|
||||
vorbis_info vi; /* struct that stores all the static vorbis bitstream
|
||||
settings */
|
||||
vorbis_comment vc; /* struct that stores all the bitstream user comments */
|
||||
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
|
||||
vorbis_block vb; /* local working space for packet->PCM decode */
|
||||
#else
|
||||
/* nix, nada, rien, nothing, nem, nüx */
|
||||
#endif
|
||||
ogg_packet op;
|
||||
vorbis_comment vc;
|
||||
struct ov_struct_st *ov;
|
||||
|
||||
uint32_t hdrsizes[3];/* stores vorbis header sizes from AVI audio header,
|
||||
maybe use ogg_uint32_t */
|
||||
//int i;
|
||||
int ret;
|
||||
char *buffer;
|
||||
ogg_packet hdr;
|
||||
//ov_struct_t *s=&sh_audio->ov;
|
||||
sh_audio->ov=malloc(sizeof(ov_struct_t));
|
||||
//s=&sh_audio->ov;
|
||||
|
||||
vorbis_info_init(&sh_audio->ov->vi);
|
||||
vorbis_comment_init(&sh_audio->ov->vc);
|
||||
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"OggVorbis: cbsize: %i\n", sh_audio->wf->cbSize);
|
||||
memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX), 3*sizeof(uint32_t));
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"OggVorbis: Read header sizes: initial: %i comment: %i codebook: %i\n", hdrsizes[0], hdrsizes[1], hdrsizes[2]);
|
||||
/*for(i=12; i <= 40; i+=2) { // header bruteforce :)
|
||||
memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+i, 3*sizeof(uint32_t));
|
||||
printf("OggVorbis: Read header sizes (%i): %ld %ld %ld\n", i, hdrsizes[0], hdrsizes[1], hdrsizes[2]);
|
||||
}*/
|
||||
|
||||
/* read headers */ // FIXME disable sound on errors here, we absolutely need this headers! - atmos
|
||||
hdr.packet=NULL;
|
||||
hdr.b_o_s = 1; /* beginning of stream for first packet */
|
||||
hdr.bytes = hdrsizes[0];
|
||||
hdr.packet = realloc(hdr.packet,hdr.bytes);
|
||||
memcpy(hdr.packet,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t),hdr.bytes);
|
||||
if(vorbis_synthesis_headerin(&sh_audio->ov->vi,&sh_audio->ov->vc,&hdr)<0)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_WARN,"OggVorbis: initial (identification) header broken!\n");
|
||||
hdr.b_o_s = 0;
|
||||
hdr.bytes = hdrsizes[1];
|
||||
hdr.packet = realloc(hdr.packet,hdr.bytes);
|
||||
memcpy(hdr.packet,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0],hdr.bytes);
|
||||
if(vorbis_synthesis_headerin(&sh_audio->ov->vi,&sh_audio->ov->vc,&hdr)<0)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_WARN,"OggVorbis: comment header broken!\n");
|
||||
hdr.bytes = hdrsizes[2];
|
||||
hdr.packet = realloc(hdr.packet,hdr.bytes);
|
||||
memcpy(hdr.packet,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1],hdr.bytes);
|
||||
if(vorbis_synthesis_headerin(&sh_audio->ov->vi,&sh_audio->ov->vc,&hdr)<0)
|
||||
/// Init the decoder with the 3 header packets
|
||||
ov = (struct ov_struct_st*)malloc(sizeof(struct ov_struct_st));
|
||||
vorbis_info_init(&ov->vi);
|
||||
vorbis_comment_init(&vc);
|
||||
op.bytes = ds_get_packet(sh_audio->ds,&op.packet);
|
||||
op.b_o_s = 1;
|
||||
/// Header
|
||||
if(vorbis_synthesis_headerin(&ov->vi,&vc,&op) <0) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_ERR,"OggVorbis: initial (identification) header broken!\n");
|
||||
driver = 0;
|
||||
free(ov);
|
||||
break;
|
||||
}
|
||||
op.bytes = ds_get_packet(sh_audio->ds,&op.packet);
|
||||
op.b_o_s = 0;
|
||||
/// Comments
|
||||
if(vorbis_synthesis_headerin(&ov->vi,&vc,&op) <0) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_ERR,"OggVorbis: comment header broken!\n");
|
||||
driver = 0;
|
||||
free(ov);
|
||||
break;
|
||||
}
|
||||
op.bytes = ds_get_packet(sh_audio->ds,&op.packet);
|
||||
//// Codebook
|
||||
if(vorbis_synthesis_headerin(&ov->vi,&vc,&op)<0) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_WARN,"OggVorbis: codebook header broken!\n");
|
||||
hdr.bytes=0;
|
||||
hdr.packet = realloc(hdr.packet,hdr.bytes); /* free */
|
||||
/* done with the headers */
|
||||
|
||||
|
||||
/* Throw the comments plus a few lines about the bitstream we're
|
||||
decoding */
|
||||
{
|
||||
char **ptr=sh_audio->ov->vc.user_comments;
|
||||
driver = 0;
|
||||
free(ov);
|
||||
break;
|
||||
} else { /// Print the infos
|
||||
char **ptr=vc.user_comments;
|
||||
while(*ptr){
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbisComment: %s\n",*ptr);
|
||||
++ptr;
|
||||
}
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Bitstream is %d channel, %ldHz, %ldkbit/s %cBR\n",sh_audio->ov->vi.channels,sh_audio->ov->vi.rate,sh_audio->ov->vi.bitrate_nominal/1000, (sh_audio->ov->vi.bitrate_lower!=sh_audio->ov->vi.bitrate_nominal)||(sh_audio->ov->vi.bitrate_upper!=sh_audio->ov->vi.bitrate_nominal)?'V':'C');
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Encoded by: %s\n",sh_audio->ov->vc.vendor);
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Bitstream is %d channel, %ldHz, %ldkbit/s %cBR\n",ov->vi.channels,ov->vi.rate,ov->vi.bitrate_nominal/1000, (ov->vi.bitrate_lower!=ov->vi.bitrate_nominal)||(ov->vi.bitrate_upper!=ov->vi.bitrate_nominal)?'V':'C');
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Encoded by: %s\n",vc.vendor);
|
||||
}
|
||||
sh_audio->channels=sh_audio->ov->vi.channels;
|
||||
sh_audio->samplerate=sh_audio->ov->vi.rate;
|
||||
sh_audio->i_bps=sh_audio->ov->vi.bitrate_nominal/8;
|
||||
|
||||
// printf("[\n");
|
||||
// sh_audio->a_buffer_len=sh_audio->audio_out_minsize;///ov->vi.channels;
|
||||
// printf("]\n");
|
||||
|
||||
/* OK, got and parsed all three headers. Initialize the Vorbis
|
||||
packet->PCM decoder. */
|
||||
vorbis_synthesis_init(&sh_audio->ov->vd,&sh_audio->ov->vi); /* central decode state */
|
||||
vorbis_block_init(&sh_audio->ov->vd,&sh_audio->ov->vb); /* local state for most of the decode
|
||||
so multiple block decodes can
|
||||
proceed in parallel. We could init
|
||||
multiple vorbis_block structures
|
||||
for vd here */
|
||||
//printf("OggVorbis: synthesis and block init done.\n");
|
||||
ogg_sync_init(&sh_audio->ov->oy); /* Now we can read pages */
|
||||
// Setup the decoder
|
||||
sh_audio->channels=ov->vi.channels;
|
||||
sh_audio->samplerate=ov->vi.rate;
|
||||
sh_audio->i_bps=ov->vi.bitrate_nominal/8;
|
||||
sh_audio->context = ov;
|
||||
|
||||
while((ret = ogg_sync_pageout(&sh_audio->ov->oy,&sh_audio->ov->og))!=1) {
|
||||
if(ret == -1)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_WARN,"OggVorbis: Pageout: not properly synced, had to skip some bytes.\n");
|
||||
else
|
||||
if(ret == 0) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Pageout: need more data to verify page, reading more data.\n");
|
||||
/* submit a a_buffer_len block to libvorbis' Ogg layer */
|
||||
buffer=ogg_sync_buffer(&sh_audio->ov->oy,256);
|
||||
ogg_sync_wrote(&sh_audio->ov->oy,demux_read_data(sh_audio->ds,buffer,256));
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Pageout: successfull.\n");
|
||||
ogg_stream_pagein(&sh_audio->ov->os,&sh_audio->ov->og); /* we can ignore any errors here
|
||||
as they'll also become apparent
|
||||
at packetout */
|
||||
|
||||
/* Get the serial number and set up the rest of decode. */
|
||||
/* serialno first; use it to set up a logical stream */
|
||||
ogg_stream_init(&sh_audio->ov->os,ogg_page_serialno(&sh_audio->ov->og));
|
||||
|
||||
/// Finish the decoder init
|
||||
vorbis_synthesis_init(&ov->vd,&ov->vi);
|
||||
vorbis_block_init(&ov->vd,&ov->vb);
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Init OK!\n");
|
||||
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
|
||||
#ifdef USE_LIBMAD
|
||||
case AFM_MAD:
|
||||
{
|
||||
@ -982,117 +915,64 @@ int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen){
|
||||
// len=MP3_DecodeFrame(buf,3);
|
||||
break;
|
||||
#ifdef HAVE_OGGVORBIS
|
||||
case AFM_VORBIS: { // OggVorbis
|
||||
/* note: good minlen would be 4k or 8k IMHO - atmos */
|
||||
int ret;
|
||||
char *buffer;
|
||||
int bytes;
|
||||
int samples;
|
||||
float **pcm;
|
||||
//ogg_int16_t convbuffer[4096];
|
||||
// int convsize;
|
||||
int readlen=1024;
|
||||
len=0;
|
||||
// convsize=minlen/sh_audio->ov->vi.channels;
|
||||
|
||||
while(len < minlen) { /* double loop allows for break in inner loop */
|
||||
while(len < minlen) { /* without aborting the outer loop - atmos */
|
||||
ret=ogg_stream_packetout(&sh_audio->ov->os,&sh_audio->ov->op);
|
||||
if(ret==0) {
|
||||
int xxx=0;
|
||||
//printf("OggVorbis: Packetout: need more data, paging!\n");
|
||||
while((ret = ogg_sync_pageout(&sh_audio->ov->oy,&sh_audio->ov->og))!=1) {
|
||||
if(ret == -1)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Pageout: not properly synced, had to skip some bytes.\n");
|
||||
else
|
||||
if(ret == 0) {
|
||||
//printf("OggVorbis: Pageout: need more data to verify page, reading more data.\n");
|
||||
/* submit a readlen k block to libvorbis' Ogg layer */
|
||||
buffer=ogg_sync_buffer(&sh_audio->ov->oy,readlen);
|
||||
bytes=demux_read_data(sh_audio->ds,buffer,readlen);
|
||||
xxx+=bytes;
|
||||
ogg_sync_wrote(&sh_audio->ov->oy,bytes);
|
||||
if(bytes==0)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: 0Bytes written, possible End of Stream\n");
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\n[sync: %d ]\n",xxx);
|
||||
//printf("OggVorbis: Pageout: successfull, pagin in.\n");
|
||||
if(ogg_stream_pagein(&sh_audio->ov->os,&sh_audio->ov->og)<0)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Pagein failed!\n");
|
||||
break;
|
||||
} else if(ret<0) {
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: Packetout: missing or corrupt data, skipping packet!\n");
|
||||
break;
|
||||
} else {
|
||||
|
||||
/* we have a packet. Decode it */
|
||||
|
||||
if(vorbis_synthesis(&sh_audio->ov->vb,&sh_audio->ov->op)==0) /* test for success! */
|
||||
vorbis_synthesis_blockin(&sh_audio->ov->vd,&sh_audio->ov->vb);
|
||||
|
||||
/* **pcm is a multichannel float vector. In stereo, for
|
||||
example, pcm[0] is left, and pcm[1] is right. samples is
|
||||
the size of each channel. Convert the float values
|
||||
(-1.<=range<=1.) to whatever PCM format and write it out */
|
||||
|
||||
while((samples=vorbis_synthesis_pcmout(&sh_audio->ov->vd,&pcm))>0){
|
||||
int i,j;
|
||||
int clipflag=0;
|
||||
int convsize=(maxlen-len)/(2*sh_audio->ov->vi.channels); // max size!
|
||||
int bout=(samples<convsize?samples:convsize);
|
||||
case AFM_VORBIS: { // Vorbis
|
||||
int samples;
|
||||
float **pcm;
|
||||
ogg_packet op;
|
||||
char* np;
|
||||
struct ov_struct_st *ov = sh_audio->context;
|
||||
len = 0;
|
||||
op.b_o_s = op.e_o_s = 0;
|
||||
while(len < minlen) {
|
||||
op.bytes = ds_get_packet(sh_audio->ds,&op.packet);
|
||||
if(!op.packet)
|
||||
break;
|
||||
if(vorbis_synthesis(&ov->vb,&op)==0) /* test for success! */
|
||||
vorbis_synthesis_blockin(&ov->vd,&ov->vb);
|
||||
while((samples=vorbis_synthesis_pcmout(&ov->vd,&pcm))>0){
|
||||
int i,j;
|
||||
int clipflag=0;
|
||||
int convsize=(maxlen-len)/(2*ov->vi.channels); // max size!
|
||||
int bout=(samples<convsize?samples:convsize);
|
||||
|
||||
if(bout<=0) break;
|
||||
if(bout<=0) break;
|
||||
|
||||
/* convert floats to 16 bit signed ints (host order) and
|
||||
interleave */
|
||||
for(i=0;i<sh_audio->ov->vi.channels;i++){
|
||||
ogg_int16_t *convbuffer=(ogg_int16_t *)(&buf[len]);
|
||||
ogg_int16_t *ptr=convbuffer+i;
|
||||
float *mono=pcm[i];
|
||||
for(j=0;j<bout;j++){
|
||||
/* convert floats to 16 bit signed ints (host order) and
|
||||
interleave */
|
||||
for(i=0;i<ov->vi.channels;i++){
|
||||
ogg_int16_t *convbuffer=(ogg_int16_t *)(&buf[len]);
|
||||
ogg_int16_t *ptr=convbuffer+i;
|
||||
float *mono=pcm[i];
|
||||
for(j=0;j<bout;j++){
|
||||
#if 1
|
||||
int val=mono[j]*32767.f;
|
||||
int val=mono[j]*32767.f;
|
||||
#else /* optional dither */
|
||||
int val=mono[j]*32767.f+drand48()-0.5f;
|
||||
int val=mono[j]*32767.f+drand48()-0.5f;
|
||||
#endif
|
||||
/* might as well guard against clipping */
|
||||
if(val>32767){
|
||||
val=32767;
|
||||
clipflag=1;
|
||||
/* might as well guard against clipping */
|
||||
if(val>32767){
|
||||
val=32767;
|
||||
clipflag=1;
|
||||
}
|
||||
if(val<-32768){
|
||||
val=-32768;
|
||||
clipflag=1;
|
||||
}
|
||||
*ptr=val;
|
||||
ptr+=ov->vi.channels;
|
||||
}
|
||||
if(val<-32768){
|
||||
val=-32768;
|
||||
clipflag=1;
|
||||
}
|
||||
*ptr=val;
|
||||
ptr+=sh_audio->ov->vi.channels;
|
||||
}
|
||||
}
|
||||
|
||||
if(clipflag)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"Clipping in frame %ld\n",(long)(sh_audio->ov->vd.sequence));
|
||||
|
||||
//fwrite(convbuffer,2*sh_audio->ov->vi.channels,bout,stderr); //dump pcm to file for debugging
|
||||
//memcpy(buf+len,convbuffer,2*sh_audio->ov->vi.channels*bout);
|
||||
len+=2*sh_audio->ov->vi.channels*bout;
|
||||
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\n[decoded: %d / %d ]\n",bout,samples);
|
||||
|
||||
vorbis_synthesis_read(&sh_audio->ov->vd,bout); /* tell libvorbis how
|
||||
many samples we
|
||||
actually consumed */
|
||||
}
|
||||
} // from else, packetout ok
|
||||
} // while len
|
||||
} // outer while len
|
||||
if(ogg_page_eos(&sh_audio->ov->og))
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_V,"OggVorbis: End of Stream reached!\n"); // FIXME clearup decoder, notify mplayer - atmos
|
||||
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\n[len: %d ]\n",len);
|
||||
|
||||
break;
|
||||
}
|
||||
if(clipflag)
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"Clipping in frame %ld\n",(long)(ov->vd.sequence));
|
||||
len+=2*ov->vi.channels*bout;
|
||||
mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\n[decoded: %d / %d ]\n",bout,samples);
|
||||
vorbis_synthesis_read(&ov->vd,bout); /* tell libvorbis how
|
||||
many samples we
|
||||
actually consumed */
|
||||
}
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
case AFM_PCM: // AVI PCM
|
||||
len=demux_read_data(sh_audio->ds,buf,minlen);
|
||||
@ -1337,13 +1217,6 @@ void resync_audio_stream(sh_audio_t *sh_audio){
|
||||
MP3_DecodeFrame(NULL,-2); // resync
|
||||
MP3_DecodeFrame(NULL,-2); // resync
|
||||
break;
|
||||
#ifdef HAVE_OGGVORBIS
|
||||
case AFM_VORBIS:
|
||||
//printf("OggVorbis: resetting stream.\n");
|
||||
ogg_sync_reset(&sh_audio->ov->oy);
|
||||
ogg_stream_reset(&sh_audio->ov->os);
|
||||
break;
|
||||
#endif
|
||||
#ifdef USE_LIBAC3
|
||||
case AFM_AC3:
|
||||
ac3_bitstream_reset(); // reset AC3 bitstream buffer
|
||||
|
@ -3,7 +3,7 @@ LIBNAME = libmpdemux.a
|
||||
|
||||
include ../config.mak
|
||||
|
||||
SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c opt-reg.c mpdemux.c
|
||||
SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c demux_mpg.c demux_viv.c demuxer.c dvdauth.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c opt-reg.c mpdemux.c demux_ogg.c
|
||||
ifeq ($(STREAMING),yes)
|
||||
SRCS += asf_streaming.c url.c http.c network.c rtp.c
|
||||
endif
|
||||
|
597
libmpdemux/demux_ogg.c
Normal file
597
libmpdemux/demux_ogg.c
Normal file
@ -0,0 +1,597 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../mp_msg.h"
|
||||
#include "../help_mp.h"
|
||||
#include "stream.h"
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
#ifndef HAVE_OGGVORBIS
|
||||
/// Some dummy function to use when no Ogg and Vorbis lib are avaible
|
||||
int demux_ogg_open(demuxer_t* demuxer) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int demux_ogg_fill_buffer(demuxer_t *d) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
demuxer_t* init_avi_with_ogg(demuxer_t* demuxer) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,MSGTR_NoOggVorbis);
|
||||
// disable audio
|
||||
demuxer->audio->id = -2;
|
||||
return demuxer;
|
||||
}
|
||||
#else
|
||||
|
||||
#include <ogg/ogg.h>
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
#define BLOCK_SIZE 1024
|
||||
|
||||
/// Vorbis decoder context : we need the vorbis_info for vorbis timestamping
|
||||
/// Shall we put this struct def in a common header ?
|
||||
typedef struct ov_struct_st {
|
||||
vorbis_info vi; /* struct that stores all the static vorbis bitstream
|
||||
settings */
|
||||
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
|
||||
vorbis_block vb; /* local working space for packet->PCM decode */
|
||||
} ov_struct_t;
|
||||
|
||||
//// OggDS headers
|
||||
// Header for the new header format
|
||||
typedef struct stream_header_video
|
||||
{
|
||||
ogg_int32_t width;
|
||||
ogg_int32_t height;
|
||||
} stream_header_video;
|
||||
|
||||
typedef struct stream_header_audio
|
||||
{
|
||||
ogg_int16_t channels;
|
||||
ogg_int16_t blockalign;
|
||||
ogg_int32_t avgbytespersec;
|
||||
} stream_header_audio;
|
||||
|
||||
typedef struct stream_header
|
||||
{
|
||||
char streamtype[8];
|
||||
char subtype[4];
|
||||
|
||||
ogg_int32_t size; // size of the structure
|
||||
|
||||
ogg_int64_t time_unit; // in reference time
|
||||
ogg_int64_t samples_per_unit;
|
||||
ogg_int32_t default_len; // in media time
|
||||
|
||||
ogg_int32_t buffersize;
|
||||
ogg_int16_t bits_per_sample;
|
||||
|
||||
union
|
||||
{
|
||||
// Video specific
|
||||
stream_header_video video;
|
||||
// Audio specific
|
||||
stream_header_audio audio;
|
||||
} sh;
|
||||
} stream_header;
|
||||
|
||||
/// Our private datas
|
||||
|
||||
/// A logical stream
|
||||
typedef struct ogg_stream {
|
||||
/// Timestamping stuff
|
||||
float samplerate; /// granulpos 2 time
|
||||
int64_t lastpos;
|
||||
int32_t lastsize;
|
||||
|
||||
// Logical stream state
|
||||
ogg_stream_state stream;
|
||||
} ogg_stream_t;
|
||||
|
||||
typedef struct ogg_demuxer {
|
||||
/// Physical stream state
|
||||
ogg_sync_state sync;
|
||||
/// Current page
|
||||
ogg_page page;
|
||||
/// Logical streams
|
||||
ogg_stream_t *subs;
|
||||
int num_sub;
|
||||
} ogg_demuxer_t;
|
||||
|
||||
/// Some defines from OggDS
|
||||
#define PACKET_TYPE_HEADER 0x01
|
||||
#define PACKET_TYPE_BITS 0x07
|
||||
#define PACKET_LEN_BITS01 0xc0
|
||||
#define PACKET_LEN_BITS2 0x02
|
||||
#define PACKET_IS_SYNCPOINT 0x08
|
||||
|
||||
|
||||
// get the logical stream of the current page
|
||||
// fill os if non NULL and return the stream id
|
||||
static int demux_ogg_get_page_stream(ogg_demuxer_t* ogg_d,ogg_stream_state** os) {
|
||||
int id,s_no;
|
||||
ogg_page* page = &ogg_d->page;
|
||||
|
||||
s_no = ogg_page_serialno(page);
|
||||
|
||||
for(id= 0; id < ogg_d->num_sub ; id++) {
|
||||
if(s_no == ogg_d->subs[id].stream.serialno)
|
||||
break;
|
||||
}
|
||||
|
||||
if(id == ogg_d->num_sub)
|
||||
return -1;
|
||||
|
||||
if(os)
|
||||
*os = &ogg_d->subs[id].stream;
|
||||
|
||||
return id;
|
||||
|
||||
}
|
||||
|
||||
/// Calculate the timestamp and add the packet to the demux stream
|
||||
// return 1 if the packet was added, 0 otherwise
|
||||
static int demux_ogg_add_packet(demux_stream_t* ds,ogg_stream_t* os,ogg_packet* pack) {
|
||||
demuxer_t* d = ds->demuxer;
|
||||
demux_packet_t* dp;
|
||||
unsigned char* data;
|
||||
float pts = 0;
|
||||
int flags = 0;
|
||||
|
||||
// If packet is an header we jump it except for vorbis
|
||||
if((*pack->packet & PACKET_TYPE_HEADER) &&
|
||||
(ds == d->video || (ds == d->audio && ((sh_audio_t*)ds->sh)->format != 0xFFFE )))
|
||||
return 0;
|
||||
|
||||
// For vorbis packet the packet is the data, for other codec we must jump the header
|
||||
if(ds == d->audio && ((sh_audio_t*)ds->sh)->format == 0xFFFE) {
|
||||
data = pack->packet;
|
||||
if(*pack->packet & PACKET_TYPE_HEADER)
|
||||
pts = 0;
|
||||
else {
|
||||
vorbis_info* vi = &((ov_struct_t*)((sh_audio_t*)ds->sh)->context)->vi;
|
||||
// When we dump the audio, there is no vi, but we dont care of timestamp in this case
|
||||
if(vi) {
|
||||
int32_t blocksize = vorbis_packet_blocksize(vi,pack) / vi->channels;
|
||||
// Calculate the timestamp if the packet don't have any
|
||||
if(pack->granulepos == -1) {
|
||||
pack->granulepos = os->lastpos;
|
||||
if(os->lastsize > 0)
|
||||
pack->granulepos += os->lastsize;
|
||||
}
|
||||
pts = pack->granulepos / (float)vi->rate;
|
||||
os->lastsize = blocksize;
|
||||
os->lastpos = pack->granulepos;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Find data start
|
||||
int16_t hdrlen = (*pack->packet & PACKET_LEN_BITS01)>>6;
|
||||
hdrlen |= (*pack->packet & PACKET_LEN_BITS2) <<1;
|
||||
data = pack->packet + 1 + hdrlen;
|
||||
// Calculate the timestamp
|
||||
if(pack->granulepos == -1)
|
||||
pack->granulepos = os->lastpos + os->lastsize;
|
||||
// If we alredy have a timestamp it can be a syncpoint
|
||||
else if(*pack->packet & PACKET_IS_SYNCPOINT)
|
||||
flags = 1;
|
||||
pts = pack->granulepos/os->samplerate;
|
||||
// Save the packet length and timestamp
|
||||
os->lastsize = 0;
|
||||
while(hdrlen) {
|
||||
os->lastsize <<= 8;
|
||||
os->lastsize |= pack->packet[hdrlen];
|
||||
hdrlen--;
|
||||
}
|
||||
os->lastpos = pack->granulepos;
|
||||
}
|
||||
|
||||
/// Send the packet
|
||||
dp = new_demux_packet(pack->bytes-(data-pack->packet));
|
||||
memcpy(dp->buffer,data,pack->bytes-(data-pack->packet));
|
||||
ds->pts = pts;
|
||||
ds->flags = flags;
|
||||
ds_add_packet(ds,dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// Open an ogg physical stream
|
||||
int demux_ogg_open(demuxer_t* demuxer) {
|
||||
ogg_demuxer_t* ogg_d;
|
||||
stream_t *s;
|
||||
char* buf;
|
||||
int np,s_no, n_audio = 0, n_video = 0;
|
||||
ogg_sync_state* sync;
|
||||
ogg_page* page;
|
||||
ogg_packet pack;
|
||||
sh_audio_t* sh_a;
|
||||
sh_video_t* sh_v;
|
||||
|
||||
s = demuxer->stream;
|
||||
|
||||
ogg_d = (ogg_demuxer_t*)calloc(1,sizeof(ogg_demuxer_t));
|
||||
sync = &ogg_d->sync;
|
||||
page = &ogg_d->page;
|
||||
|
||||
ogg_sync_init(&ogg_d->sync);
|
||||
|
||||
while(1) {
|
||||
/// Try to get a page
|
||||
np = ogg_sync_pageout(sync,page);
|
||||
/// Error
|
||||
if(np < 0) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"OGG demuxer : Bad page sync\n");
|
||||
return 0;
|
||||
}
|
||||
/// Need some more data
|
||||
if(np <= 0) {
|
||||
int len;
|
||||
buf = ogg_sync_buffer(sync,BLOCK_SIZE);
|
||||
len = stream_read(s,buf,BLOCK_SIZE);
|
||||
if(len == 0 && s->eof) {
|
||||
free(ogg_d);
|
||||
return 0;
|
||||
}
|
||||
ogg_sync_wrote(sync,len);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We got one page now
|
||||
|
||||
if( ! ogg_page_bos(page) ) { // It's not a begining page
|
||||
// Header parsing end here, we need to get the page otherwise it will be lost
|
||||
int id = demux_ogg_get_page_stream(ogg_d,NULL);
|
||||
if(id >= 0)
|
||||
ogg_stream_pagein(&ogg_d->subs[id].stream,page);
|
||||
else
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"OGG : Warning found none bos page from unknow stream %d\n",ogg_page_serialno(page));
|
||||
break;
|
||||
}
|
||||
|
||||
/// Init the data structure needed for a logical stream
|
||||
ogg_d->subs = (ogg_stream_t*)realloc(ogg_d->subs,(ogg_d->num_sub+1)*sizeof(ogg_stream_t));
|
||||
memset(&ogg_d->subs[ogg_d->num_sub],0,sizeof(ogg_stream_t));
|
||||
/// Get the stream serial number
|
||||
s_no = ogg_page_serialno(page);
|
||||
ogg_stream_init(&ogg_d->subs[ogg_d->num_sub].stream,s_no);
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"OGG : Found a stream with serial=%d\n",s_no);
|
||||
// Take the first page
|
||||
ogg_stream_pagein(&ogg_d->subs[ogg_d->num_sub].stream,page);
|
||||
// Get first packet of the page
|
||||
ogg_stream_packetout(&ogg_d->subs[ogg_d->num_sub].stream,&pack);
|
||||
|
||||
// Reset our vars
|
||||
sh_a = NULL;
|
||||
sh_v = NULL;
|
||||
|
||||
// Check for Vorbis
|
||||
if(pack.bytes >= 7 && ! strncmp(&pack.packet[1],"vorbis", 6) ) {
|
||||
sh_a = new_sh_audio(demuxer,ogg_d->num_sub);
|
||||
sh_a->format = 0xFFFE;
|
||||
n_audio++;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"OGG : stream %d is vorbis\n",ogg_d->num_sub);
|
||||
|
||||
/// Check for old header
|
||||
} else if(pack.bytes >= 142 && ! strncmp(&pack.packet[1],"Direct Show Samples embedded in Ogg",35) ) {
|
||||
|
||||
// Old video header
|
||||
if(*(int32_t*)(pack.packet+96) == 0x05589f80 && pack.bytes >= 184) {
|
||||
sh_v = new_sh_video(demuxer,ogg_d->num_sub);
|
||||
sh_v->bih = (BITMAPINFOHEADER*)calloc(1,sizeof(BITMAPINFOHEADER));
|
||||
sh_v->format = mmioFOURCC(pack.packet[68],pack.packet[69],
|
||||
pack.packet[70],pack.packet[71]);
|
||||
sh_v->frametime = (*(int64_t*)(pack.packet+164))*0.0000001;
|
||||
sh_v->fps = 1/sh_v->frametime;
|
||||
sh_v->disp_w = sh_v->bih->biWidth = *(int32_t*)(pack.packet+176);
|
||||
sh_v->disp_h = sh_v->bih->biHeight = *(int32_t*)(pack.packet+180);
|
||||
sh_v->bih->biBitCount = *(int16_t*)(pack.packet+182);
|
||||
|
||||
ogg_d->subs[ogg_d->num_sub].samplerate = sh_v->fps;
|
||||
n_video++;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"OGG stream %d is video\n",ogg_d->num_sub);
|
||||
|
||||
// Old audio header
|
||||
} else if(*(int32_t*)pack.packet+96 == 0x05589F81) {
|
||||
unsigned int extra_size;
|
||||
sh_a = new_sh_audio(demuxer,ogg_d->num_sub);
|
||||
extra_size = *(int16_t*)(pack.packet+140);
|
||||
sh_a->wf = (WAVEFORMATEX*)calloc(1,sizeof(WAVEFORMATEX)+extra_size);
|
||||
sh_a->format = sh_a->wf->wFormatTag = *(int16_t*)(pack.packet+124);
|
||||
sh_a->channels = sh_a->wf->nChannels = *(int16_t*)(pack.packet+126);
|
||||
sh_a->samplerate = sh_a->wf->nSamplesPerSec = *(int32_t*)(pack.packet+128);
|
||||
sh_a->wf->nAvgBytesPerSec = *(int32_t*)(pack.packet+132);
|
||||
sh_a->wf->nBlockAlign = *(int16_t*)(pack.packet+136);
|
||||
sh_a->wf->wBitsPerSample = *(int16_t*)(pack.packet+138);
|
||||
sh_a->samplesize = (sh_a->wf->wBitsPerSample+7)/8;
|
||||
sh_a->wf->cbSize = extra_size;
|
||||
if(extra_size > 0)
|
||||
memcpy(sh_a->wf+sizeof(WAVEFORMATEX),pack.packet+142,extra_size);
|
||||
|
||||
ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate * sh_a->channels;
|
||||
n_audio++;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"OGG stream %d is audio\n",ogg_d->num_sub);
|
||||
} else
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"OGG stream %d contain an old header but the header type is unknow\n",ogg_d->num_sub);
|
||||
|
||||
// Check new header
|
||||
} else if ( (*pack.packet & PACKET_TYPE_BITS ) == PACKET_TYPE_HEADER &&
|
||||
pack.bytes >= (int)sizeof(stream_header)+1) {
|
||||
stream_header *st = (stream_header*)(pack.packet+1);
|
||||
/// New video header
|
||||
if(strncmp(st->streamtype,"video",5) == 0) {
|
||||
sh_v = new_sh_video(demuxer,ogg_d->num_sub);
|
||||
sh_v->bih = (BITMAPINFOHEADER*)calloc(1,sizeof(BITMAPINFOHEADER));
|
||||
sh_v->format = mmioFOURCC(st->subtype[0],st->subtype[1],
|
||||
st->subtype[2],st->subtype[3]);
|
||||
sh_v->frametime = st->time_unit*0.0000001;
|
||||
sh_v->fps = 1/sh_v->frametime;
|
||||
sh_v->bih->biSize = st->buffersize;
|
||||
sh_v->bih->biBitCount = st->bits_per_sample;
|
||||
sh_v->disp_w = sh_v->bih->biWidth = st->sh.video.width;
|
||||
sh_v->disp_h = sh_v->bih->biHeight = st->sh.video.height;
|
||||
|
||||
ogg_d->subs[ogg_d->num_sub].samplerate= sh_v->fps;
|
||||
n_video++;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"OGG stream %d is video\n",ogg_d->num_sub);
|
||||
/// New audio header
|
||||
} else if(strncmp(st->streamtype,"audio",5) == 0) {
|
||||
char buffer[5];
|
||||
unsigned int extra_size = st->size - sizeof(stream_header);
|
||||
memcpy(buffer,st->subtype,4);
|
||||
buffer[4] = '\0';
|
||||
sh_a = new_sh_audio(demuxer,ogg_d->num_sub);
|
||||
sh_a->wf = (WAVEFORMATEX*)calloc(1,sizeof(WAVEFORMATEX)+extra_size);
|
||||
sh_a->format = sh_a->wf->wFormatTag = atoi(buffer);
|
||||
sh_a->channels = sh_a->wf->nChannels = st->sh.audio.channels;
|
||||
sh_a->samplerate = sh_a->wf->nSamplesPerSec = st->samples_per_unit;
|
||||
sh_a->wf->nAvgBytesPerSec = st->sh.audio.avgbytespersec;
|
||||
sh_a->wf->nBlockAlign = st->sh.audio.blockalign;
|
||||
sh_a->wf->wBitsPerSample = st->bits_per_sample;
|
||||
sh_a->samplesize = (sh_a->wf->wBitsPerSample+7)/8;
|
||||
sh_a->wf->cbSize = extra_size;
|
||||
if(extra_size)
|
||||
memcpy(sh_a->wf+sizeof(WAVEFORMATEX),st+1,extra_size);
|
||||
|
||||
ogg_d->subs[ogg_d->num_sub].samplerate = sh_a->samplerate * sh_a->channels;
|
||||
n_audio++;
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"OGG stream %d is audio\n",ogg_d->num_sub);
|
||||
|
||||
/// Check for text (subtitles) header
|
||||
} else if(strncmp(st->streamtype,"text",4) == 0) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"OGG text stream are not supported\n");
|
||||
//// Unknow header type
|
||||
} else
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"OGG stream %d has a header marker but is of an unknow type\n",ogg_d->num_sub);
|
||||
/// Unknow (invalid ?) header
|
||||
} else
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"OGG stream %d is of an unknow type\n",ogg_d->num_sub);
|
||||
|
||||
if(sh_a || sh_v) {
|
||||
demux_stream_t* ds = NULL;
|
||||
if(sh_a) {
|
||||
// If the audio stream is not defined we took the first one
|
||||
if(demuxer->audio->id == -1) {
|
||||
demuxer->audio->id = ogg_d->num_sub;
|
||||
demuxer->audio->sh = sh_a;
|
||||
sh_a->ds = demuxer->audio;
|
||||
}
|
||||
/// Is it the stream we want
|
||||
if(demuxer->audio->id == ogg_d->num_sub)
|
||||
ds = demuxer->audio;
|
||||
}
|
||||
if(sh_v) {
|
||||
/// Also for video
|
||||
if(demuxer->video->id == -1) {
|
||||
demuxer->video->id = ogg_d->num_sub;
|
||||
demuxer->video->sh = sh_v;
|
||||
sh_v->ds = demuxer->video;
|
||||
}
|
||||
if(demuxer->video->id == ogg_d->num_sub)
|
||||
ds = demuxer->video;
|
||||
}
|
||||
/// Add the packet contained in this page
|
||||
if(ds) {
|
||||
/// Finish the page, otherwise packets will be lost
|
||||
do {
|
||||
demux_ogg_add_packet(ds,&ogg_d->subs[ogg_d->num_sub],&pack);
|
||||
} while(ogg_stream_packetout(&ogg_d->subs[ogg_d->num_sub].stream,&pack) == 1);
|
||||
|
||||
}
|
||||
}
|
||||
ogg_d->num_sub++;
|
||||
}
|
||||
|
||||
/// Finish to setup the demuxer
|
||||
demuxer->priv = ogg_d;
|
||||
/// We can't seek :(
|
||||
demuxer->seekable = 0;
|
||||
|
||||
if(!n_video)
|
||||
demuxer->video->id = -2;
|
||||
if(!n_audio)
|
||||
demuxer->audio->id = -2;
|
||||
|
||||
mp_msg(MSGT_DEMUX,MSGL_V,"OGG demuxer : found %d audio stream and %d video stream\n",n_audio,n_video);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int demux_ogg_fill_buffer(demuxer_t *d) {
|
||||
ogg_demuxer_t* ogg_d;
|
||||
stream_t *s;
|
||||
demux_stream_t *ds;
|
||||
ogg_sync_state* sync;
|
||||
ogg_stream_state* os;
|
||||
ogg_page* page;
|
||||
ogg_packet pack;
|
||||
int np = 0, id=0;
|
||||
|
||||
s = d->stream;
|
||||
ogg_d = d->priv;
|
||||
sync = &ogg_d->sync;
|
||||
page = &ogg_d->page;
|
||||
|
||||
/// Find the stream we are working on
|
||||
if ( (id = demux_ogg_get_page_stream(ogg_d,&os)) < 0) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"OGG demuxer : can't get current stream\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
np = 0;
|
||||
ds = NULL;
|
||||
/// Try to get some packet from the current page
|
||||
while( (np = ogg_stream_packetout(os,&pack)) != 1) {
|
||||
/// No packet we go the next page
|
||||
if(np == 0) {
|
||||
while(1) {
|
||||
int pa,len;
|
||||
char *buf;
|
||||
/// Get the next page from the physical stream
|
||||
while( (pa = ogg_sync_pageout(sync,page)) != 1) {
|
||||
/// Error : we skip some bytes
|
||||
if(pa < 0) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"OGG : Page out not synced, we skip some bytes\n");
|
||||
continue;
|
||||
}
|
||||
/// We need more data
|
||||
buf = ogg_sync_buffer(sync,BLOCK_SIZE);
|
||||
len = stream_read(s,buf,BLOCK_SIZE);
|
||||
if(len == 0 && s->eof) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"OGG : Stream EOF !!!!\n");
|
||||
return 0;
|
||||
}
|
||||
ogg_sync_wrote(sync,len);
|
||||
} /// Page loop
|
||||
|
||||
/// Find the page's logical stream
|
||||
if( (id = demux_ogg_get_page_stream(ogg_d,&os)) < 0) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"OGG demuxer error : we met an unknow stream\n");
|
||||
return 0;
|
||||
}
|
||||
/// Take the page
|
||||
if(ogg_stream_pagein(os,page) == 0)
|
||||
break;
|
||||
/// Page was invalid => retry
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"OGG demuxer : got invalid page !!!!!\n");
|
||||
}
|
||||
} else /// Packet was corrupted
|
||||
mp_msg(MSGT_DEMUX,MSGL_WARN,"OGG : bad packet in stream %d\n",id);
|
||||
} /// Packet loop
|
||||
|
||||
/// Is the actual logical stream in use ?
|
||||
if(id == d->audio->id)
|
||||
ds = d->audio;
|
||||
else if(id == d->video->id)
|
||||
ds = d->video;
|
||||
|
||||
if(ds) {
|
||||
if(!demux_ogg_add_packet(ds,&ogg_d->subs[id],&pack))
|
||||
continue; /// Unuseful packet, get another
|
||||
return 1;
|
||||
}
|
||||
|
||||
} /// while(1)
|
||||
|
||||
}
|
||||
|
||||
/// For avi with Ogg audio stream we have to create an ogg demuxer for this
|
||||
// stream, then we join the avi and ogg demuxer with a demuxers demuxer
|
||||
demuxer_t* init_avi_with_ogg(demuxer_t* demuxer) {
|
||||
demuxer_t *od;
|
||||
ogg_demuxer_t *ogg_d;
|
||||
stream_t* s;
|
||||
uint32_t hdrsizes[3];
|
||||
demux_packet_t *dp;
|
||||
sh_audio_t *sh_audio = demuxer->audio->sh;
|
||||
int np;
|
||||
unsigned char *p = NULL,*buf;
|
||||
int plen;
|
||||
|
||||
/// Check that the cbSize is enouth big for the following reads
|
||||
if(sh_audio->wf->cbSize < 3*sizeof(uint32_t)) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI OGG : Initial audio header is too small !!!!!\n");
|
||||
goto fallback;
|
||||
}
|
||||
/// Get the size of the 3 header packet
|
||||
memcpy(hdrsizes, ((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX), 3*sizeof(uint32_t));
|
||||
|
||||
/// Check the size
|
||||
if(sh_audio->wf->cbSize < 3*sizeof(uint32_t) + sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1] + hdrsizes[2]) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI OGG : Audio header is too small !!!!!\n");
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
// Build the ogg demuxer private datas
|
||||
ogg_d = (ogg_demuxer_t*)calloc(1,sizeof(ogg_demuxer_t));
|
||||
ogg_d->num_sub = 1;
|
||||
ogg_d->subs = (ogg_stream_t*)malloc(sizeof(ogg_stream_t));
|
||||
|
||||
// Init the ogg physical stream
|
||||
ogg_sync_init(&ogg_d->sync);
|
||||
|
||||
// Get the first page of the stream : we assume there only 1 logical stream
|
||||
while((np = ogg_sync_pageout(&ogg_d->sync,&ogg_d->page)) <= 0 ) {
|
||||
if(np < 0) {
|
||||
mp_msg(MSGT_DEMUX,MSGL_ERR,"AVI OGG error : Can't init using first stream packets\n");
|
||||
free(ogg_d);
|
||||
goto fallback;
|
||||
}
|
||||
// Add some data
|
||||
plen = ds_get_packet(demuxer->audio,&p);
|
||||
buf = ogg_sync_buffer(&ogg_d->sync,plen);
|
||||
memcpy(buf,p,plen);
|
||||
ogg_sync_wrote(&ogg_d->sync,plen);
|
||||
}
|
||||
// Init the logical stream
|
||||
mp_msg(MSGT_DEMUX,MSGL_DBG2,"AVI OGG found page with serial %d\n",ogg_page_serialno(&ogg_d->page));
|
||||
ogg_stream_init(&ogg_d->subs[0].stream,ogg_page_serialno(&ogg_d->page));
|
||||
// Write the page
|
||||
ogg_stream_pagein(&ogg_d->subs[0].stream,&ogg_d->page);
|
||||
|
||||
// Create the ds_stream and the ogg demuxer
|
||||
s = new_ds_stream(demuxer->audio);
|
||||
od = new_demuxer(s,DEMUXER_TYPE_OGG,0,-2,-2);
|
||||
|
||||
/// Add the header packets in the ogg demuxer audio stream
|
||||
// Initial header
|
||||
dp = new_demux_packet(hdrsizes[0]);
|
||||
memcpy(dp->buffer,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t),hdrsizes[0]);
|
||||
ds_add_packet(od->audio,dp);
|
||||
/// Comments
|
||||
dp = new_demux_packet(hdrsizes[1]);
|
||||
memcpy(dp->buffer,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0],hdrsizes[1]);
|
||||
ds_add_packet(od->audio,dp);
|
||||
/// Code book
|
||||
dp = new_demux_packet(hdrsizes[2]);
|
||||
memcpy(dp->buffer,((unsigned char*)sh_audio->wf)+2*sizeof(WAVEFORMATEX)+3*sizeof(uint32_t)+hdrsizes[0]+hdrsizes[1],hdrsizes[2]);
|
||||
ds_add_packet(od->audio,dp);
|
||||
|
||||
// Finish setting up the ogg demuxer
|
||||
od->priv = ogg_d;
|
||||
sh_audio = new_sh_audio(od,0);
|
||||
od->audio->id = 0;
|
||||
od->video->id = -2;
|
||||
od->audio->sh = sh_audio;
|
||||
sh_audio->ds = od->audio;
|
||||
sh_audio->format = 0xFFFE;
|
||||
|
||||
/// Return the joined demuxers
|
||||
return new_demuxers_demuxer(demuxer,od,demuxer);
|
||||
|
||||
fallback:
|
||||
demuxer->audio->id = -2;
|
||||
return demuxer;
|
||||
|
||||
}
|
||||
|
||||
/// TODO : Seeking 8-)
|
||||
|
||||
#endif
|
@ -218,6 +218,7 @@ extern int demux_open_tv(demuxer_t *demuxer, tvi_handle_t *tvh);
|
||||
int demux_y4m_fill_buffer(demuxer_t *demux);
|
||||
int demux_audio_fill_buffer(demux_stream_t *ds);
|
||||
extern int demux_demuxers_fill_buffer(demuxer_t *demux,demux_stream_t *ds);
|
||||
extern int demux_ogg_fill_buffer(demuxer_t *d);
|
||||
|
||||
int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){
|
||||
// Note: parameter 'ds' can be NULL!
|
||||
@ -243,6 +244,7 @@ int demux_fill_buffer(demuxer_t *demux,demux_stream_t *ds){
|
||||
case DEMUXER_TYPE_Y4M: return demux_y4m_fill_buffer(demux);
|
||||
case DEMUXER_TYPE_AUDIO: return demux_audio_fill_buffer(ds);
|
||||
case DEMUXER_TYPE_DEMUXERS: return demux_demuxers_fill_buffer(demux,ds);
|
||||
case DEMUXER_TYPE_OGG: return demux_ogg_fill_buffer(demux);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -434,6 +436,9 @@ extern void demux_open_real(demuxer_t *demuxer);
|
||||
extern int nuv_check_file(demuxer_t *demuxer);
|
||||
extern void demux_open_nuv(demuxer_t *demuxer);
|
||||
extern int demux_audio_open(demuxer_t* demuxer);
|
||||
extern int demux_ogg_open(demuxer_t* demuxer);
|
||||
|
||||
extern demuxer_t* init_avi_with_ogg(demuxer_t* demuxer);
|
||||
|
||||
|
||||
static demuxer_t* demux_open_stream(stream_t *stream,int file_format,int audio_id,int video_id,int dvdsub_id){
|
||||
@ -593,6 +598,17 @@ if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_ROQ){
|
||||
demuxer = NULL;
|
||||
}
|
||||
}
|
||||
//=============== Try to open as Ogg file: =================
|
||||
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_OGG){
|
||||
demuxer=new_demuxer(stream,DEMUXER_TYPE_OGG,audio_id,video_id,dvdsub_id);
|
||||
if(demux_ogg_open(demuxer)){
|
||||
mp_msg(MSGT_DEMUXER,MSGL_INFO,"Detected OGG format\n");
|
||||
file_format=DEMUXER_TYPE_OGG;
|
||||
} else {
|
||||
free_demuxer(demuxer);
|
||||
demuxer = NULL;
|
||||
}
|
||||
}
|
||||
//=============== Try to open as MPEG-PS file: =================
|
||||
if(file_format==DEMUXER_TYPE_UNKNOWN || file_format==DEMUXER_TYPE_MPEG_PS){
|
||||
int pes=1;
|
||||
@ -719,7 +735,12 @@ switch(file_format){
|
||||
break;
|
||||
}
|
||||
case DEMUXER_TYPE_AVI: {
|
||||
return (demuxer_t*) demux_open_avi(demuxer);
|
||||
sh_audio_t* sh_a;
|
||||
demuxer = (demuxer_t*) demux_open_avi(demuxer);
|
||||
sh_a = (sh_audio_t*)demuxer->audio->sh;
|
||||
if(demuxer->audio->id != -2 && sh_a && sh_a->format == 0xFFFE)
|
||||
demuxer = init_avi_with_ogg(demuxer);
|
||||
return demuxer;
|
||||
// break;
|
||||
}
|
||||
case DEMUXER_TYPE_NUV: {
|
||||
|
@ -22,9 +22,10 @@
|
||||
#define DEMUXER_TYPE_ROQ 15
|
||||
#define DEMUXER_TYPE_MF 16
|
||||
#define DEMUXER_TYPE_AUDIO 17
|
||||
#define DEMUXER_TYPE_OGG 18
|
||||
// This should always match the higest demuxer type number.
|
||||
// Unless you want to disallow users to force the demuxer to some types
|
||||
#define DEMUXER_TYPE_MAX 17
|
||||
#define DEMUXER_TYPE_MAX 18
|
||||
|
||||
#define DEMUXER_TYPE_DEMUXERS (1<<16)
|
||||
// A virtual demuxer type for the network code
|
||||
@ -167,6 +168,8 @@ void ds_free_packs(demux_stream_t *ds);
|
||||
int ds_get_packet(demux_stream_t *ds,unsigned char **start);
|
||||
int ds_get_packet_sub(demux_stream_t *ds,unsigned char **start);
|
||||
|
||||
// This is defined here because demux_stream_t ins't defined in stream.h
|
||||
stream_t* new_ds_stream(demux_stream_t *ds);
|
||||
|
||||
static inline int avi_stream_id(unsigned int id){
|
||||
unsigned char *p=(unsigned char *)&id;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "help_mp.h"
|
||||
|
||||
#include "stream.h"
|
||||
#include "demuxer.h"
|
||||
|
||||
extern int verbose; // defined in mplayer.c
|
||||
|
||||
@ -75,6 +76,9 @@ int stream_fill_buffer(stream_t *s){
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case STREAMTYPE_DS:
|
||||
len = demux_read_data((demux_stream_t*)s->priv,s->buffer,STREAM_BUFFER_SIZE);
|
||||
break;
|
||||
default: len=0;
|
||||
}
|
||||
if(len<=0){ s->eof=1; s->buf_pos=s->buf_len=0; return 0; }
|
||||
@ -236,3 +240,8 @@ void free_stream(stream_t *s){
|
||||
free(s);
|
||||
}
|
||||
|
||||
stream_t* new_ds_stream(demux_stream_t *ds) {
|
||||
stream_t* s = new_stream(-1,STREAMTYPE_DS);
|
||||
s->priv = ds;
|
||||
return s;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#define STREAMTYPE_TV 5
|
||||
#define STREAMTYPE_PLAYLIST 6
|
||||
#define STREAMTYPE_MF 7
|
||||
#define STREAMTYPE_DS 8
|
||||
|
||||
#define VCD_SECTOR_SIZE 2352
|
||||
#define VCD_SECTOR_OFFS 24
|
||||
|
Loading…
Reference in New Issue
Block a user