📄 demux_ogg.c
字号:
#include "config.h"#ifdef HAVE_OGGVORBIS#include <stdlib.h>#include <stdio.h>#include <string.h>#include <assert.h>#include <math.h>#include "../mp_msg.h"#include "../help_mp.h"#include "stream.h"#include "demuxer.h"#include "stheader.h"#define FOURCC_VORBIS mmioFOURCC('v', 'r', 'b', 's')#define FOURCC_THEORA mmioFOURCC('t', 'h', 'e', 'o')#ifdef TREMOR#include <tremor/ogg.h>#include <tremor/ivorbiscodec.h>#else#include <ogg/ogg.h>#include <vorbis/codec.h>#endif#ifdef HAVE_OGGTHEORA#include <theora/theora.h>#endif#define BLOCK_SIZE 4096/// 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_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 */ float rg_scale; /* replaygain scale */#ifdef TREMOR int rg_scale_int;#endif} ov_struct_t;/* Theora decoder context : we won't be able to interpret granule positions * without using theora_granule_time with the theora_state of the stream. * This is duplicated in `vd_theora.c'; put this in a common header? */#ifdef HAVE_OGGTHEORAtypedef struct theora_struct_st { theora_state st; theora_comment cc; theora_info inf;} theora_struct_t;#endif//// OggDS headers// Header for the new header formattypedef 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 __attribute__((__packed__)) 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; ogg_int16_t padding; union { // Video specific stream_header_video video; // Audio specific stream_header_audio audio; } sh;} stream_header;/// Our private datastypedef struct ogg_syncpoint { int64_t granulepos; off_t page_pos;} ogg_syncpoint_t;/// A logical streamtypedef struct ogg_stream { /// Timestamping stuff float samplerate; /// granulpos 2 time int64_t lastpos; int32_t lastsize; // Logical stream state ogg_stream_state stream; int hdr_packets; int vorbis; int theora; int flac; int text; int id;} 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_syncpoint_t* syncpoints; int num_syncpoint; off_t pos, last_size; int64_t final_granulepos; /* Used for subtitle switching. */ int n_text; int *text_ids; char **text_langs;} ogg_demuxer_t;#define NUM_VORBIS_HDR_PACKETS 3/// 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 0x08extern int index_mode;extern char *dvdsub_lang, *audio_lang;extern int dvdsub_id;extern int demux_aid_vid_mismatch;//-------- subtitle support - should be moved to decoder layer, and queue// - subtitles up in demuxer buffer...#include "../subreader.h"#include "../libvo/sub.h"#define OGG_SUB_MAX_LINE 128static subtitle ogg_sub;extern subtitle* vo_sub;static float clear_sub;//FILE* subout;staticuint16_t get_uint16 (const void *buf){ uint16_t ret; unsigned char *tmp; tmp = (unsigned char *) buf; ret = tmp[1] & 0xff; ret = (ret << 8) + (tmp[0] & 0xff); return (ret);}staticuint32_t get_uint32 (const void *buf){ uint32_t ret; unsigned char *tmp; tmp = (unsigned char *) buf; ret = tmp[3] & 0xff; ret = (ret << 8) + (tmp[2] & 0xff); ret = (ret << 8) + (tmp[1] & 0xff); ret = (ret << 8) + (tmp[0] & 0xff); return (ret);}staticuint64_t get_uint64 (const void *buf){ uint64_t ret; unsigned char *tmp; tmp = (unsigned char *) buf; ret = tmp[7] & 0xff; ret = (ret << 8) + (tmp[6] & 0xff); ret = (ret << 8) + (tmp[5] & 0xff); ret = (ret << 8) + (tmp[4] & 0xff); ret = (ret << 8) + (tmp[3] & 0xff); ret = (ret << 8) + (tmp[2] & 0xff); ret = (ret << 8) + (tmp[1] & 0xff); ret = (ret << 8) + (tmp[0] & 0xff); return (ret);}void demux_ogg_init_sub () { int lcv; if(!ogg_sub.text[0]) // not yet allocated for (lcv = 0; lcv < SUB_MAX_TEXT; lcv++) { ogg_sub.text[lcv] = (char*)malloc(OGG_SUB_MAX_LINE); }}void demux_ogg_add_sub (ogg_stream_t* os,ogg_packet* pack) { int lcv; int line_pos = 0; int ignoring = 0; char *packet = pack->packet; mp_msg(MSGT_DEMUX,MSGL_DBG2,"\ndemux_ogg_add_sub %02X %02X %02X '%s'\n", (unsigned char)packet[0], (unsigned char)packet[1], (unsigned char)packet[2], &packet[3]); ogg_sub.lines = 0; if (((unsigned char)packet[0]) == 0x88) { // some subtitle text // Find data start int32_t duration = 0; int16_t hdrlen = (*packet & PACKET_LEN_BITS01)>>6, i; hdrlen |= (*packet & PACKET_LEN_BITS2) <<1; lcv = 1 + hdrlen; for (i = hdrlen; i > 0; i--) { duration <<= 8; duration |= (unsigned char)packet[i]; } if ((hdrlen > 0) && (duration > 0)) { float pts; if(pack->granulepos == -1) pack->granulepos = os->lastpos + os->lastsize; pts = (float)pack->granulepos/(float)os->samplerate; clear_sub = 1.0 + pts + (float)duration/1000.0; } while (1) { int c = packet[lcv++]; if(c=='\n' || c==0 || line_pos >= OGG_SUB_MAX_LINE-1){ ogg_sub.text[ogg_sub.lines][line_pos] = 0; // close sub if(line_pos) ogg_sub.lines++; if(!c || ogg_sub.lines>=SUB_MAX_TEXT) break; // EOL or TooMany line_pos = 0; } switch (c) { case '\r': case '\n': // just ignore linefeeds for now // their placement seems rather haphazard break; case '<': // some html markup, ignore for now ignoring = 1; break; case '>': ignoring = 0; break; default: if(!ignoring) ogg_sub.text[ogg_sub.lines][line_pos++] = c; break; } } } mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg sub lines: %d first: '%s'\n", ogg_sub.lines, ogg_sub.text[0]);#ifdef USE_ICONV subcp_recode1(&ogg_sub);#endif vo_sub = &ogg_sub; vo_osd_changed(OSDTYPE_SUBTITLE);}// get the logical stream of the current page// fill os if non NULL and return the stream idstatic 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) { // If we have only one vorbis stream allow the stream id to change // it's normal on radio stream (each song have an different id). // But we (or the codec?) should check that the samplerate, etc // doesn't change (for radio stream it's ok) if(ogg_d->num_sub == 1 && ogg_d->subs[0].vorbis) { ogg_stream_reset(&ogg_d->subs[0].stream); ogg_stream_init(&ogg_d->subs[0].stream,s_no); id = 0; } else return -1; } if(os) *os = &ogg_d->subs[id].stream; return id;}static unsigned char* demux_ogg_read_packet(ogg_stream_t* os,ogg_packet* pack,void *context,float* pts,int* flags, int samplesize) { unsigned char* data; *pts = 0; *flags = 0; if(os->vorbis) { data = pack->packet; if(*pack->packet & PACKET_TYPE_HEADER) os->hdr_packets++; else if (context ) { vorbis_info *vi = &((ov_struct_t*)context)->vi; // When we dump the audio, there is no vi, but we don't care of timestamp in this case int32_t blocksize = vorbis_packet_blocksize(vi,pack) / samplesize; // 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; }# ifdef HAVE_OGGTHEORA } else if (os->theora) { /* we pass complete packets to theora, mustn't strip the header! */ data = pack->packet; os->lastsize = 1; /* header packets beginn on 1-bit: thus check (*data&0x80). We don't have theora_state st, until all header packets were passed to the decoder. */ if (context != NULL && !(*data&0x80)) { theora_info *thi = ((theora_struct_t*)context)->st.i; int keyframe_granule_shift=_ilog(thi->keyframe_frequency_force-1); int64_t iframemask = (1 << keyframe_granule_shift) - 1; if (pack->granulepos >= 0) { os->lastpos = pack->granulepos >> keyframe_granule_shift; os->lastpos += pack->granulepos & iframemask; *flags = ((pack->granulepos & iframemask) == 0); } else { os->lastpos++; } pack->granulepos = os->lastpos; *pts = (double)os->lastpos / (double)os->samplerate;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -