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 + -
显示快捷键?