demux_ogg.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 1,617 行 · 第 1/4 页
C
1,617 行
#include "config.h"#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include <assert.h>#include <math.h>#include <inttypes.h>#include "mp_msg.h"#include "help_mp.h"#include "stream/stream.h"#include "demuxer.h"#include "stheader.h"#include "libavutil/intreadwrite.h"#define FOURCC_VORBIS mmioFOURCC('v', 'r', 'b', 's')#define FOURCC_SPEEX mmioFOURCC('s', 'p', 'x', ' ')#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>extern int _ilog (unsigned int); /* defined in many places in theora/lib/ */#endif#undef memcpy#define memcpy uc_memcpy#define BLOCK_SIZE 4096/* 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 speex; int theora; int flac; int text; int id; vorbis_info vi; int vi_inited; void *ogg_d;} 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 char *dvdsub_lang, *audio_lang;extern int dvdsub_id;//-------- 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;//FILE* subout;#define get_uint16(b) AV_RL16(b)#define get_uint32(b) AV_RL32(b)#define get_uint64(b) AV_RL64(b)void demux_ogg_add_sub (ogg_stream_t* os,ogg_packet* pack) { int lcv; char *packet = pack->packet; if (pack->bytes < 4) return; 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]); if (((unsigned char)packet[0]) == 0x88) { // some subtitle text // Find data start double endpts = MP_NOPTS_VALUE; int32_t duration = 0; int16_t hdrlen = (*packet & PACKET_LEN_BITS01)>>6, i; hdrlen |= (*packet & PACKET_LEN_BITS2) <<1; lcv = 1 + hdrlen; if (pack->bytes < lcv) return; 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; endpts = 1.0 + pts + (float)duration/1000.0; } sub_clear_text(&ogg_sub, MP_NOPTS_VALUE); sub_add_text(&ogg_sub, &packet[lcv], pack->bytes - lcv, endpts); } mp_msg(MSGT_DEMUX,MSGL_DBG2,"Ogg sub lines: %d first: '%s'\n", ogg_sub.lines, ogg_sub.text[0]);#ifdef USE_ICONV subcp_recode(&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 = pack->packet; *pts = 0; *flags = 0; if(os->vorbis) { if(*pack->packet & PACKET_TYPE_HEADER) os->hdr_packets++; else if (os->vi_inited) { vorbis_info *vi; int32_t blocksize; // When we dump the audio, there is no vi, but we don't care of timestamp in this case vi = &(os->vi); 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; } } else if (os->speex) { // whole packet (default)# ifdef HAVE_OGGTHEORA } else if (os->theora) { /* we pass complete packets to theora, mustn't strip the header! */ 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; }#endif /* HAVE_OGGTHEORA */ } else if (os->flac) { /* we pass complete packets to flac, mustn't strip the header! */ if (os->flac == 2 && pack->packet[0] != 0xff) return NULL; } else { if(*pack->packet & PACKET_TYPE_HEADER) os->hdr_packets++; 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 ? os->lastsize : 1); // If we already have a timestamp it can be a syncpoint 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; } } return data;}// check if clang has substring from comma separated langliststatic int demux_ogg_check_lang(const char *clang, char *langlist){ char *c; if (!langlist || !*langlist) return 0; while ((c = strchr(langlist, ','))) { if (!strncasecmp(clang, langlist, c - langlist)) return 1; langlist = &c[1]; } if (!strncasecmp(clang, langlist, strlen(langlist))) return 1; return 0;}static int demux_ogg_sub_reverse_id(demuxer_t *demuxer, int id);/// Try to print out comments and also check for LANGUAGE= tagstatic void demux_ogg_check_comments(demuxer_t *d, ogg_stream_t *os, int id, vorbis_comment *vc){ const char *hdr, *val; char **cmt = vc->user_comments; int index, i; ogg_demuxer_t *ogg_d = (ogg_demuxer_t *)d->priv; struct table { const char *ogg; const char *mp; } table[] = { { "ENCODED_USING", "Software" }, { "ENCODER_URL", "Encoder URL" }, { "TITLE", "Name" }, { "ARTIST", "Artist" }, { "COMMENT", "Comments" }, { "DATE", "Creation Date" }, { "GENRE", "Genre" }, { "ALBUM", "Album" }, { "TRACKNUMBER", "Track" }, { NULL, NULL }, }; while(*cmt) { hdr = NULL; if (!strncasecmp(*cmt, "LANGUAGE=", 9)) { val = *cmt + 9; if (ogg_d->subs[id].text) mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_SID_%d_LANG=%s\n", ogg_d->subs[id].id, val); else if (id != d->video->id) mp_msg(MSGT_IDENTIFY, MSGL_INFO, "ID_AID_%d_LANG=%s\n", ogg_d->subs[id].id, val); if (ogg_d->subs[id].text) mp_msg(MSGT_DEMUX, MSGL_INFO, "[Ogg] Language for -sid %d is '-slang \"%s\"'\n", ogg_d->subs[id].id, val); // copy this language name into the array index = demux_ogg_sub_reverse_id(d, id); if (index >= 0) { // in case of malicious files with more than one lang per track: if (ogg_d->text_langs[index]) free(ogg_d->text_langs[index]); ogg_d->text_langs[index] = strdup(val); } // check for -slang if subs are uninitialized yet if (os->text && d->sub->id < 0 && demux_ogg_check_lang(val, dvdsub_lang)) { d->sub->id = index; dvdsub_id = index; mp_msg(MSGT_DEMUX, MSGL_V, "Ogg demuxer: Displaying subtitle stream id %d which matched -slang %s\n", id, val); } else hdr = "Language"; } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?