aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--libmpdemux/demux_mpg.c1248
-rw-r--r--libmpdemux/demuxer.c51
-rw-r--r--libmpdemux/demuxer.h7
-rw-r--r--libmpdemux/mp3_hdr.c144
-rw-r--r--libmpdemux/mp3_hdr.h36
-rw-r--r--libmpdemux/mpeg_hdr.c539
-rw-r--r--libmpdemux/mpeg_hdr.h55
-rw-r--r--libmpdemux/parse_es.c158
-rw-r--r--libmpdemux/parse_es.h45
-rw-r--r--libmpdemux/video.c515
11 files changed, 2795 insertions, 7 deletions
diff --git a/Makefile b/Makefile
index f66d69e792..34e4bdef8f 100644
--- a/Makefile
+++ b/Makefile
@@ -234,6 +234,10 @@ SRCS_COMMON = asxparser.c \
libmpdemux/demux_lavf.c \
libmpdemux/demux_mf.c \
libmpdemux/demux_mkv.c \
+ libmpdemux/demux_mpg.c \
+ libmpdemux/mp3_hdr.c \
+ libmpdemux/parse_es.c \
+ libmpdemux/mpeg_hdr.c \
libmpdemux/demux_rawaudio.c \
libmpdemux/demux_rawvideo.c \
libmpdemux/ebml.c \
diff --git a/libmpdemux/demux_mpg.c b/libmpdemux/demux_mpg.c
new file mode 100644
index 0000000000..44ec85d2db
--- /dev/null
+++ b/libmpdemux/demux_mpg.c
@@ -0,0 +1,1248 @@
+/*
+ * MPG/VOB file parser for DEMUXER v2.5
+ * copyright (c) 2001 by A'rpi/ESP-team
+ *
+ * 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 <math.h>
+
+#include "config.h"
+#include "mp_msg.h"
+#include "options.h"
+
+#include "libavutil/attributes.h"
+#include "libmpcodecs/dec_audio.h"
+#include "stream/stream.h"
+#include "demuxer.h"
+#include "parse_es.h"
+#include "stheader.h"
+#include "mp3_hdr.h"
+
+//#define MAX_PS_PACKETSIZE 2048
+#define MAX_PS_PACKETSIZE (224*1024)
+
+#define UNKNOWN 0
+#define VIDEO_MPEG1 0x10000001
+#define VIDEO_MPEG2 0x10000002
+#define VIDEO_MPEG4 0x10000004
+#define VIDEO_H264 0x10000005
+#define AUDIO_MP2 0x50
+#define AUDIO_A52 0x2000
+#define AUDIO_LPCM_BE 0x10001
+#define AUDIO_AAC mmioFOURCC('M', 'P', '4', 'A')
+
+typedef struct mpg_demuxer {
+ float last_pts;
+ float first_pts; // first pts found in stream
+ float first_to_final_pts_len; // difference between final pts and first pts
+ int has_valid_timestamps; // !=0 iff time stamps look linear
+ // (not necessarily starting with 0)
+ unsigned int es_map[0x40]; //es map of stream types (associated to the pes id) from 0xb0 to 0xef
+ int num_a_streams;
+ int a_stream_ids[MAX_A_STREAMS];
+} mpg_demuxer_t;
+
+static int mpeg_pts_error=0;
+off_t ps_probe = 0;
+
+static int parse_psm(demuxer_t *demux, int len) {
+ unsigned char c, id, type;
+ unsigned int plen, prog_len, es_map_len;
+ mpg_demuxer_t *priv = (mpg_demuxer_t *) demux->priv;
+
+ mp_dbg(MSGT_DEMUX,MSGL_V, "PARSE_PSM, len=%d\n", len);
+ if(! len || len > 1018)
+ return 0;
+
+ c = stream_read_char(demux->stream);
+ if(! (c & 0x80)) {
+ stream_skip(demux->stream, len - 1); //not yet valid, discard
+ return 0;
+ }
+ stream_skip(demux->stream, 1);
+ prog_len = stream_read_word(demux->stream); //length of program descriptors
+ stream_skip(demux->stream, prog_len); //.. that we ignore
+ es_map_len = stream_read_word(demux->stream); //length of elementary streams map
+ es_map_len = FFMIN(es_map_len, len - prog_len - 8); //sanity check
+ while(es_map_len > 0) {
+ type = stream_read_char(demux->stream);
+ id = stream_read_char(demux->stream);
+ if(id >= 0xB0 && id <= 0xEF && priv) {
+ int idoffset = id - 0xB0;
+ switch(type) {
+ case 0x1:
+ priv->es_map[idoffset] = VIDEO_MPEG1;
+ break;
+ case 0x2:
+ priv->es_map[idoffset] = VIDEO_MPEG2;
+ break;
+ case 0x3:
+ case 0x4:
+ priv->es_map[idoffset] = AUDIO_MP2;
+ break;
+ case 0x0f:
+ case 0x11:
+ priv->es_map[idoffset] = AUDIO_AAC;
+ break;
+ case 0x10:
+ priv->es_map[idoffset] = VIDEO_MPEG4;
+ break;
+ case 0x1b:
+ priv->es_map[idoffset] = VIDEO_H264;
+ break;
+ case 0x81:
+ priv->es_map[idoffset] = AUDIO_A52;
+ break;
+ }
+ mp_dbg(MSGT_DEMUX,MSGL_V, "PSM ES, id=0x%x, type=%x, stype: %x\n", id, type, priv->es_map[idoffset]);
+ }
+ plen = stream_read_word(demux->stream); //length of elementary stream descriptors
+ plen = FFMIN(plen, es_map_len); //sanity check
+ stream_skip(demux->stream, plen); //skip descriptors for now
+ es_map_len -= 4 + plen;
+ }
+ stream_skip(demux->stream, 4); //skip crc32
+ return 1;
+}
+
+// 500000 is a wild guess
+#define TIMESTAMP_PROBE_LEN 500000
+
+//MAX_PTS_DIFF_FOR_CONSECUTIVE denotes the maximum difference
+//between two pts to consider them consecutive
+//1.0 is a wild guess
+#define MAX_PTS_DIFF_FOR_CONSECUTIVE 1.0
+
+//returns the first pts found within TIME_STAMP_PROBE_LEN bytes after stream_pos in demuxer's stream.
+//if no pts is found or an error occurs, -1.0 is returned.
+//Packs are freed.
+static float read_first_mpeg_pts_at_position(demuxer_t* demuxer, off_t stream_pos)
+{
+ stream_t *s = demuxer->stream;
+ mpg_demuxer_t *mpg_d = demuxer->priv;
+ float pts = -1.0; //the pts to return;
+ float found_pts1; //the most recently found pts
+ float found_pts2; //the pts found before found_pts1
+ float found_pts3; //the pts found before found_pts2
+ int found = 0;
+
+ if(!mpg_d || stream_pos < 0)
+ return pts;
+
+ found_pts3 = found_pts2 = found_pts1 = mpg_d->last_pts;
+ stream_seek(s, stream_pos);
+
+ //We look for pts.
+ //However, we do not stop at the first found one, as timestamps may reset
+ //Therefore, we seek until we found three consecutive
+ //pts within MAX_PTS_DIFF_FOR_CONSECUTIVE.
+
+ while(found<3 && !s->eof
+ && (fabsf(found_pts2-found_pts1) < MAX_PTS_DIFF_FOR_CONSECUTIVE)
+ && (fabsf(found_pts3-found_pts2) < MAX_PTS_DIFF_FOR_CONSECUTIVE)
+ && (stream_tell(s) < stream_pos + TIMESTAMP_PROBE_LEN)
+ && ds_fill_buffer(demuxer->video))
+ {
+ if(mpg_d->last_pts != found_pts1)
+ {
+ if(!found)
+ found_pts3 = found_pts2 = found_pts1 = mpg_d->last_pts; //the most recently found pts
+ else
+ {
+ found_pts3 = found_pts2;
+ found_pts2 = found_pts1;
+ found_pts1 = mpg_d->last_pts;
+ }
+ found++;
+ }
+ }
+
+ if(found == 3) pts = found_pts3;
+
+ //clean up from searching of first pts;
+ demux_flush(demuxer);
+
+ return pts;
+}
+
+/// Open an mpg physical stream
+static demuxer_t* demux_mpg_open(demuxer_t* demuxer) {
+ stream_t *s = demuxer->stream;
+ mpg_demuxer_t* mpg_d;
+
+ if (!ds_fill_buffer(demuxer->video)) return 0;
+ mpg_d = calloc(1,sizeof(mpg_demuxer_t));
+ if(mpg_d)
+ {
+ demuxer->priv = mpg_d;
+ mpg_d->last_pts = -1.0;
+ mpg_d->first_pts = -1.0;
+
+ //if seeking is allowed set has_valid_timestamps if appropriate
+ if(demuxer->seekable
+ && (demuxer->stream->type == STREAMTYPE_FILE
+ || demuxer->stream->type == STREAMTYPE_VCD)
+ && demuxer->movi_start != demuxer-> movi_end
+ )
+ {
+ //We seek to the beginning of the stream, to somewhere in the
+ //middle, and to the end of the stream, while remembering the pts
+ //at each of the three positions. With these pts, we check whether
+ //or not the pts are "linear enough" to justify seeking by the pts
+ //of the stream
+
+ //The position where the stream is now
+ off_t pos = stream_tell(s);
+ float first_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_start);
+ if(first_pts != -1.0)
+ {
+ float middle_pts = read_first_mpeg_pts_at_position(demuxer, (demuxer->movi_end + demuxer->movi_start)/2);
+ if(middle_pts != -1.0)
+ {
+ float final_pts = read_first_mpeg_pts_at_position(demuxer, demuxer->movi_end - TIMESTAMP_PROBE_LEN);
+ if(final_pts != -1.0)
+ {
+ // found proper first, middle, and final pts.
+ float proportion = (middle_pts-first_pts==0) ? -1 : (final_pts-middle_pts)/(middle_pts-first_pts);
+ // if they are linear enough set has_valid_timestamps
+ if((0.5 < proportion) && (proportion < 2))
+ {
+ mpg_d->first_pts = first_pts;
+ mpg_d->first_to_final_pts_len = final_pts - first_pts;
+ mpg_d->has_valid_timestamps = 1;
+ }
+ }
+ }
+ }
+
+ //Cleaning up from seeking in stream
+ demuxer->stream->eof=0;
+ demuxer->video->eof=0;
+ demuxer->audio->eof=0;
+
+ stream_seek(s,pos);
+ ds_fill_buffer(demuxer->video);
+ } // if ( demuxer->seekable )
+ } // if ( mpg_d )
+ return demuxer;
+}
+
+static void demux_close_mpg(demuxer_t* demuxer) {
+ mpg_demuxer_t* mpg_d = demuxer->priv;
+ free(mpg_d);
+}
+
+
+static unsigned long long read_mpeg_timestamp(stream_t *s,int c){
+ unsigned int d,e;
+ unsigned long long pts;
+ d=stream_read_word(s);
+ e=stream_read_word(s);
+ if( ((c&1)!=1) || ((d&1)!=1) || ((e&1)!=1) ){
+ ++mpeg_pts_error;
+ return 0; // invalid pts
+ }
+ pts=(((uint64_t)((c>>1)&7))<<30)|((d>>1)<<15)|(e>>1);
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3," pts {%llu}",pts);
+ return pts;
+}
+
+static void new_audio_stream(demuxer_t *demux, int aid){
+ if(!demux->a_streams[aid]){
+ mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demux->priv;
+ sh_audio_t* sh_a;
+ new_sh_audio(demux,aid);
+ sh_a = (sh_audio_t*)demux->a_streams[aid];
+ sh_a->needs_parsing = 1;
+ switch(aid & 0xE0){ // 1110 0000 b (high 3 bit: type low 5: id)
+ case 0x00: sh_a->format=0x50;break; // mpeg
+ case 0xA0: sh_a->format=0x10001;break; // dvd pcm
+ case 0x80: if((aid & 0xF8) == 0x88) sh_a->format=0x2001;//dts
+ else sh_a->format=0x2000;break; // ac3
+ }
+ //evo files
+ if((aid & 0xC0) == 0xC0) sh_a->format=0x2000;
+ else if(aid >= 0x98 && aid <= 0x9f) sh_a->format=0x2001;
+ if (mpg_d) mpg_d->a_stream_ids[mpg_d->num_a_streams++] = aid;
+ }
+ if(demux->audio->id==-1) demux->audio->id=aid;
+}
+
+static int demux_mpg_read_packet(demuxer_t *demux,int id){
+ int d av_unused;
+ int len;
+ int set_pts=0; // !=0 iff pts has been set to a proper value
+ unsigned char c=0;
+ unsigned long long pts=0;
+ unsigned long long dts av_unused = 0;
+ int l;
+ int pes_ext2_subid=-1;
+ double stream_pts = MP_NOPTS_VALUE;
+ demux_stream_t *ds=NULL;
+ demux_packet_t* dp;
+ mpg_demuxer_t *priv = (mpg_demuxer_t *) demux->priv;
+
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3,"demux_read_packet: %X\n",id);
+
+// if(id==0x1F0){
+// demux->synced=0; // force resync after 0x1F0
+// return -1;
+//}
+
+// if(id==0x1BA) packet_start_pos=stream_tell(demux->stream);
+ if((id<0x1BC || id>=0x1F0) && id != 0x1FD) return -1;
+ if(id==0x1BE) return -1; // padding stream
+ if(id==0x1BF) return -1; // private2
+
+ len=stream_read_word(demux->stream);
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3,"PACKET len=%d",len);
+// if(len==62480){ demux->synced=0;return -1;} /* :) */
+ if(len==0 || len>MAX_PS_PACKETSIZE){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"Invalid PS packet len: %d\n",len);
+ return -2; // invalid packet !!!!!!
+ }
+
+ mpeg_pts_error=0;
+
+ if(id==0x1BC) {
+ parse_psm(demux, len);
+ return 0;
+ }
+
+ while(len>0){ // Skip stuFFing bytes
+ c=stream_read_char(demux->stream);
+ --len;
+ if(c!=0xFF)break;
+ }
+ if((c>>6)==1){ // Read (skip) STD scale & size value
+// printf(" STD_scale=%d",(c>>5)&1);
+ d=((c&0x1F)<<8)|stream_read_char(demux->stream);
+ len-=2;
+// printf(" STD_size=%d",d);
+ c=stream_read_char(demux->stream);
+ }
+ // Read System-1 stream timestamps:
+ if((c>>4)==2){
+ pts=read_mpeg_timestamp(demux->stream,c);
+ set_pts=1;
+ len-=4;
+ } else
+ if((c>>4)==3){
+ pts=read_mpeg_timestamp(demux->stream,c);
+ c=stream_read_char(demux->stream);
+ if((c>>4)!=1) pts=0; //printf("{ERROR4}");
+ else set_pts = 1;
+ dts=read_mpeg_timestamp(demux->stream,c);
+ len-=4+1+4;
+ } else
+ if((c>>6)==2){
+ int pts_flags;
+ int hdrlen;
+ int parse_ext2;
+ // System-2 (.VOB) stream:
+ c=stream_read_char(demux->stream);
+ pts_flags=c>>6;
+ parse_ext2 = (id == 0x1FD) && ((c & 0x3F) == 1);
+ c=stream_read_char(demux->stream);
+ hdrlen=c;
+ len-=2;
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3," hdrlen=%d (len=%d)",hdrlen,len);
+ if(hdrlen>len){ mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: invalid header length \n"); return -1;}
+ if(pts_flags==2 && hdrlen>=5){
+ c=stream_read_char(demux->stream);
+ pts=read_mpeg_timestamp(demux->stream,c);
+ set_pts=1;
+ len-=5;hdrlen-=5;
+ } else
+ if(pts_flags==3 && hdrlen>=10){
+ c=stream_read_char(demux->stream);
+ pts=read_mpeg_timestamp(demux->stream,c);
+ set_pts=1;
+ c=stream_read_char(demux->stream);
+ dts=read_mpeg_timestamp(demux->stream,c);
+ len-=10;hdrlen-=10;
+ }
+ len-=hdrlen;
+ if(parse_ext2 && hdrlen>=3) {
+ c=stream_read_char(demux->stream);
+ hdrlen--;
+
+ if((c & 0x0F) != 0x0F) {
+ mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: pes_extension_flag2 not set, discarding pes packet\n");
+ return -1;
+ }
+ if(c & 0x80) { //pes_private_data_flag
+ if(hdrlen<16) {
+ mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: not enough pes_private_data bytes: %d < 16, discarding pes packet\n", hdrlen);
+ return -1;
+ }
+ stream_skip(demux->stream, 16);
+ hdrlen-=16;
+ }
+ if(c & 0x40) { //pack_header_field_flag
+ int l = stream_read_char(demux->stream);
+ if(l < 0) //couldn't read from the stream?
+ return -1;
+ hdrlen--;
+ if(l < 0 || hdrlen < l) {
+ mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: not enough pack_header bytes: hdrlen: %d < skip: %d, discarding pes packet\n",
+ hdrlen, l);
+ return -1;
+ }
+ stream_skip(demux->stream, l);
+ hdrlen-=l;
+ }
+ if(c & 0x20) { //program_packet_sequence_counter_flag
+ if(hdrlen < 2) {
+ mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: not enough program_packet bytes: hdrlen: %d, discarding pes packet\n", hdrlen);
+ return -1;
+ }
+ stream_skip(demux->stream, 2);
+ hdrlen-=2;
+ }
+ if(c & 0x10) {
+ //STD
+ stream_skip(demux->stream, 2);
+ hdrlen-=2;
+ }
+ c=stream_read_char(demux->stream); //pes_extension2 flag
+ hdrlen--;
+ if(c!=0x81) { mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: unknown pes_extension2 format, len is > 1 \n"); return -1;}
+ c=stream_read_char(demux->stream); //pes_extension2 payload === substream id
+ hdrlen--;
+ if(c<0x55 || c>0x5F) { mp_msg(MSGT_DEMUX,MSGL_V,"demux_mpg: unknown vc1 substream_id: 0x%x \n", c); return -1;}
+ pes_ext2_subid=c;
+ }
+ if(hdrlen>0)
+ stream_skip(demux->stream,hdrlen); // skip header and stuffing bytes
+
+ if(id==0x1FD && pes_ext2_subid!=-1) {
+ //==== EVO VC1 STREAMS ===//
+ if(!demux->v_streams[pes_ext2_subid]) new_sh_video(demux,pes_ext2_subid);
+ if(demux->video->id==-1) demux->video->id=pes_ext2_subid;
+ if(demux->video->id==pes_ext2_subid){
+ ds=demux->video;
+ if(!ds->sh) ds->sh=demux->v_streams[pes_ext2_subid];
+ if(priv && ds->sh) {
+ sh_video_t *sh = (sh_video_t *)ds->sh;
+ sh->format = mmioFOURCC('W', 'V', 'C', '1');
+ }
+ }
+ }
+ //============== DVD Audio sub-stream ======================
+ if(id==0x1BD){
+ int aid, rawa52 = 0;
+ off_t tmppos;
+ unsigned int tmp;
+
+ tmppos = stream_tell(demux->stream);
+ tmp = stream_read_word(demux->stream);
+ stream_seek(demux->stream, tmppos);
+ /// vdr stores A52 without the 4 header bytes, so we have to check this condition first
+ if(tmp == 0x0B77) {
+ aid = 128;
+ rawa52 = 1;
+ }
+ else {
+ aid=stream_read_char(demux->stream);--len;
+ if(len<3) return -1; // invalid audio packet
+ }
+
+ // AID:
+ // 0x20..0x3F subtitle
+ // 0x80..0x87 and 0xC0..0xCF AC3 audio
+ // 0x88..0x8F and 0x98..0x9F DTS audio
+ // 0xA0..0xBF PCM audio
+
+ if((aid & 0xE0) == 0x20){
+ // subtitle:
+ aid&=0x1F;
+
+ if(!demux->s_streams[aid]){
+ sh_sub_t *sh = new_sh_sub(demux, aid);
+ if (sh) sh->type = 'v';
+ mp_msg(MSGT_DEMUX,MSGL_V,"==> Found subtitle: %d\n",aid);
+ }
+
+ if(demux->sub->id > -1)
+ demux->sub->id &= 0x1F;
+ if(!demux->opts->sub_lang && demux->sub->id == -1)
+ demux->sub->id = aid;
+ if(demux->sub->id==aid){
+ ds=demux->sub;
+ }
+ } else if((aid >= 0x80 && aid <= 0x8F) || (aid >= 0x98 && aid <= 0xAF) || (aid >= 0xC0 && aid <= 0xCF)) {
+
+// aid=128+(aid&0x7F);
+ // aid=0x80..0xBF
+ new_audio_stream(demux, aid);
+ if(demux->audio->id==aid){
+ int type;
+ ds=demux->audio;
+ if(!ds->sh) ds->sh=demux->a_streams[aid];
+ // READ Packet: Skip additional audio header data:
+ if(!rawa52) {
+ c=stream_read_char(demux->stream);//num of frames
+ type=stream_read_char(demux->stream);//startpos hi
+ type=(type<<8)|stream_read_char(demux->stream);//startpos lo
+// printf("\r[%02X][%04X]",c,type);
+ len-=3;
+ }
+ if((aid&0xE0)==0xA0 && len>=3){
+ unsigned char* hdr;
+ // save audio header as codecdata!
+ if(!((sh_audio_t*)(ds->sh))->codecdata_len){
+ ((sh_audio_t*)(ds->sh))->codecdata=malloc(3);
+ ((sh_audio_t*)(ds->sh))->codecdata_len=3;
+ }
+ hdr=((sh_audio_t*)(ds->sh))->codecdata;
+ // read LPCM header:
+ // emphasis[1], mute[1], rvd[1], frame number[5]:
+ hdr[0]=stream_read_char(demux->stream);
+// printf(" [%01X:%02d]",c>>5,c&31);
+ // quantization[2],freq[2],rvd[1],channels[3]
+ hdr[1]=stream_read_char(demux->stream);
+// printf("[%01X:%01X] ",c>>4,c&15);
+ // dynamic range control (0x80=off):
+ hdr[2]=stream_read_char(demux->stream);
+// printf("[%02X] ",c);
+ len-=3;
+ if(len<=0) mp_msg(MSGT_DEMUX,MSGL_V,"End of packet while searching for PCM header\n");
+ }
+// printf(" \n");
+ } // if(demux->audio->id==aid)
+
+ } else mp_msg(MSGT_DEMUX,MSGL_V,"Unknown 0x1BD substream: 0x%02X \n",aid);
+ } //if(id==0x1BD)
+ } else {
+ if(c!=0x0f){
+ mp_msg(MSGT_DEMUX,MSGL_V," {ERROR5,c=%d} \n",c);
+ return -1; // invalid packet !!!!!!
+ }
+ }
+ if(mpeg_pts_error) mp_msg(MSGT_DEMUX,MSGL_V," {PTS_err:%d} \n",mpeg_pts_error);
+ mp_dbg(MSGT_DEMUX,MSGL_DBG3," => len=%d\n",len);
+
+// if(len<=0 || len>MAX_PS_PACKETSIZE) return -1; // Invalid packet size
+ if(len<=0 || len>MAX_PS_PACKETSIZE){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"Invalid PS data len: %d\n",len);
+ return -1; // invalid packet !!!!!!
+ }
+
+ if(id>=0x1C0 && id<=0x1DF){
+ // mpeg audio
+ int aid=id-0x1C0;
+ new_audio_stream(demux, aid);
+ if(demux->audio->id==aid){
+ ds=demux->audio;
+ if(!ds->sh) ds->sh=demux->a_streams[aid];
+ if(priv && ds->sh) {
+ sh_audio_t *sh = (sh_audio_t *)ds->sh;
+ if(priv->es_map[id - 0x1B0])
+ sh->format = priv->es_map[id - 0x1B0];
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"ASSIGNED TO STREAM %d CODEC %x\n", id, priv->es_map[id - 0x1B0]);
+ }
+ }
+ } else
+ if(id>=0x1E0 && id<=0x1EF){
+ // mpeg video
+ int aid=id-0x1E0;
+ if(!demux->v_streams[aid]) new_sh_video(demux,aid);
+ if(demux->video->id==-1) demux->video->id=aid;
+ if(demux->video->id==aid){
+ ds=demux->video;
+ if(!ds->sh) ds->sh=demux->v_streams[aid];
+ if(priv && ds->sh) {
+ sh_video_t *sh = (sh_video_t *)ds->sh;
+ if(priv->es_map[id - 0x1B0]) {
+ sh->format = priv->es_map[id - 0x1B0];
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"ASSIGNED TO STREAM %d CODEC %x\n", id, priv->es_map[id - 0x1B0]);
+ }
+ }
+ }
+ }
+
+ if(ds){
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_MPG: Read %d data bytes from packet %04X\n",len,id);
+// printf("packet start = 0x%X \n",stream_tell(demux->stream)-packet_start_pos);
+
+ dp=new_demux_packet(len);
+ if(!dp) {
+ mp_dbg(MSGT_DEMUX,MSGL_ERR,"DEMUX_MPG ERROR: couldn't create demux_packet(%d bytes)\n",len);
+ stream_skip(demux->stream,len);
+ return 0;
+ }
+ l = stream_read(demux->stream,dp->buffer,len);
+ if(l<len)
+ resize_demux_packet(dp, l);
+ len = l;
+ if(set_pts)
+ dp->pts=pts/90000.0f;
+ dp->pos=demux->filepos;
+ /*
+ workaround:
+ set dp->stream_pts only when feeding the video stream, or strangely interleaved files
+ (such as SWIII) will show strange alternations in the stream time, wildly going
+ back and forth
+ */
+ if(ds == demux->video && stream_control(demux->stream, STREAM_CTRL_GET_CURRENT_TIME,(void *)&stream_pts)!=STREAM_UNSUPPORTED)
+ dp->stream_pts = stream_pts;
+ ds_add_packet(ds,dp);
+ if (demux->priv && set_pts) ((mpg_demuxer_t*)demux->priv)->last_pts = pts/90000.0f;
+// if(ds==demux->sub) parse_dvdsub(ds->last->buffer,ds->last->len);
+ return 1;
+ }
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"DEMUX_MPG: Skipping %d data bytes from packet %04X\n",len,id);
+ if(len<=2356) stream_skip(demux->stream,len);
+ return 0;
+}
+
+static int num_elementary_packets100=0;
+static int num_elementary_packets101=0;
+static int num_elementary_packets12x=0;
+static int num_elementary_packets1B6=0;
+static int num_elementary_packetsPES=0;
+static int num_mpeg12_startcode=0;
+static int num_h264_slice=0; //combined slice
+static int num_h264_dpa=0; //DPA Slice
+static int num_h264_dpb=0; //DPB Slice
+static int num_h264_dpc=0; //DPC Slice
+static int num_h264_idr=0; //IDR Slice
+static int num_h264_sps=0;
+static int num_h264_pps=0;
+
+static int num_mp3audio_packets=0;
+
+static void clear_stats(void)
+{
+ num_elementary_packets100=0;
+ num_elementary_packets101=0;
+ num_elementary_packets1B6=0;
+ num_elementary_packets12x=0;
+ num_elementary_packetsPES=0;
+ num_mpeg12_startcode=0;
+ num_h264_slice=0; //combined slice
+ num_h264_dpa=0; //DPA Slice
+ num_h264_dpb=0; //DPB Slice
+ num_h264_dpc=0; //DPC Slice
+ num_h264_idr=0; //IDR Slice
+ num_h264_sps=0;
+ num_h264_pps=0;
+ num_mp3audio_packets=0;
+}
+
+//assumes demuxer->synced < 2
+static inline void update_stats(int head)
+{
+ if(head==0x1B6) ++num_elementary_packets1B6;
+ else if(head==0x1B3 || head==0x1B8) ++num_mpeg12_startcode;
+ else if(head==0x100) ++num_elementary_packets100;
+ else if(head==0x101) ++num_elementary_packets101;
+ else if(head==0x1BD || (0x1C0<=head && head<=0x1EF))
+ num_elementary_packetsPES++;
+ else if(head>=0x120 && head<=0x12F) ++num_elementary_packets12x;
+ if(head>=0x100 && head<0x1B0)
+ {
+ if((head&~0x60) == 0x101) ++num_h264_slice;
+ else if((head&~0x60) == 0x102) ++num_h264_dpa;
+ else if((head&~0x60) == 0x103) ++num_h264_dpb;
+ else if((head&~0x60) == 0x104) ++num_h264_dpc;
+ else if((head&~0x60) == 0x105 && head != 0x105) ++num_h264_idr;
+ else if((head&~0x60) == 0x107 && head != 0x107) ++num_h264_sps;
+ else if((head&~0x60) == 0x108 && head != 0x108) ++num_h264_pps;
+ }
+}
+
+static int demux_mpg_probe(demuxer_t *demuxer) {
+ int pes av_unused = 1;
+ int tmp;
+ off_t tmppos;
+ int file_format = DEMUXER_TYPE_UNKNOWN;
+
+ tmppos=stream_tell(demuxer->stream);
+ tmp=stream_read_dword(demuxer->stream);
+ if(tmp==0x1E0 || tmp==0x1C0) {
+ tmp=stream_read_word(demuxer->stream);
+ if(tmp>1 && tmp<=2048) pes=0; // demuxer->synced=3; // PES...
+ }
+ stream_seek(demuxer->stream,tmppos);
+
+ clear_stats();
+
+ if(demux_mpg_open(demuxer))
+ file_format=DEMUXER_TYPE_MPEG_PS;
+ else {
+ mp_msg(MSGT_DEMUX,MSGL_V,"MPEG packet stats: p100: %d p101: %d p1B6: %d p12x: %d sli: %d a: %d b: %d c: %d idr: %d sps: %d pps: %d PES: %d MP3: %d, synced: %d\n",
+ num_elementary_packets100,num_elementary_packets101,
+ num_elementary_packets1B6,num_elementary_packets12x,
+ num_h264_slice, num_h264_dpa,
+ num_h264_dpb, num_h264_dpc=0,
+ num_h264_idr, num_h264_sps=0,
+ num_h264_pps,
+ num_elementary_packetsPES,num_mp3audio_packets, demuxer->synced);
+
+ //MPEG packet stats: p100: 458 p101: 458 PES: 0 MP3: 1103 (.m2v)
+ if(num_mp3audio_packets>50 && num_mp3audio_packets>2*num_elementary_packets100
+ && abs(num_elementary_packets100-num_elementary_packets101)>2)
+ return file_format;
+
+ // some hack to get meaningfull error messages to our unhappy users:
+ if(num_mpeg12_startcode>=2 && num_elementary_packets100>=2 && num_elementary_packets101>=2 &&
+ abs(num_elementary_packets101+8-num_elementary_packets100)<16) {
+ if(num_elementary_packetsPES>=4 && num_elementary_packetsPES>=num_elementary_packets100-4) {
+ return file_format;
+ }
+ file_format=DEMUXER_TYPE_MPEG_ES; // <-- hack is here :)
+ } else
+ // fuzzy mpeg4-es detection. do NOT enable without heavy testing of mpeg formats detection!
+ if(num_elementary_packets1B6>3 && num_elementary_packets12x>=1 &&
+ num_elementary_packetsPES==0 && num_elementary_packets100<=num_elementary_packets12x &&
+ demuxer->synced<2) {
+ file_format=DEMUXER_TYPE_MPEG4_ES;
+ } else
+ // fuzzy h264-es detection. do NOT enable without heavy testing of mpeg formats detection!
+ if((num_h264_slice>3 || (num_h264_dpa>3 && num_h264_dpb>3 && num_h264_dpc>3)) &&
+ /* FIXME num_h264_sps>=1 && */ num_h264_pps>=1 && num_h264_idr>=1 &&
+ num_elementary_packets1B6==0 && num_elementary_packetsPES==0 &&
+ demuxer->synced<2) {
+ file_format=DEMUXER_TYPE_H264_ES;
+ } else
+ {
+ if(demuxer->synced==2)
+ mp_msg(MSGT_DEMUXER, MSGL_ERR, "MPEG: %s",
+ mp_gtext("Missing video stream!? Contact the author, it may be a bug :(\n"));
+ else
+ mp_tmsg(MSGT_DEMUXER,MSGL_V,"Not MPEG System Stream format... (maybe Transport Stream?)\n");
+ }
+ }
+ //FIXME this shouldn't be necessary
+ stream_seek(demuxer->stream,tmppos);
+ return file_format;
+}
+
+static int demux_mpg_es_fill_buffer(demuxer_t *demux, demux_stream_t *ds){
+ // Elementary video stream
+ if(demux->stream->eof) return 0;
+ demux->filepos=stream_tell(demux->stream);
+ ds_read_packet(demux->video,demux->stream,STREAM_BUFFER_SIZE,0,demux->filepos,0);
+ return 1;
+}
+
+/**
+ * \brief discard until 0x100 header and return a filled buffer
+ * \param b buffer-end pointer
+ * \param pos current pos in stream, negative since b points to end of buffer
+ * \param s stream to read from
+ * \return new position, differs from original pos when eof hit and thus
+ * b was modified to point to the new end of buffer
+ */
+static int find_end(unsigned char **b, int pos, stream_t *s) {
+ register int state = 0xffffffff;
+ unsigned char *buf = *b;
+ int start = pos;
+ int read, unused;
+ // search already read part
+ while (state != 0x100 && pos) {
+ state = state << 8 | buf[pos++];
+ }
+ // continue search in stream
+ while (state != 0x100) {
+ register int c = stream_read_char(s);
+ if (c < 0) break;
+ state = state << 8 | c;
+ }
+ // modify previous header (from 0x1bc or 0x1bf to 0x100)
+ buf[start++] = 0;
+ // copy remaining buffer part to current pos
+ memmove(&buf[start], &buf[pos], -pos);
+ unused = start + -pos; // -unused bytes in buffer
+ read = stream_read(s, &buf[unused], -unused);
+ unused += read;
+ // fix buffer so it ends at pos == 0 (eof case)
+ *b = &buf[unused];
+ start -= unused;
+ return start;
+}
+
+/**
+ * This format usually uses an insane bitrate, which makes this function
+ * performance-critical!
+ * Be sure to benchmark any changes with different compiler versions.
+ */
+static int demux_mpg_gxf_fill_buffer(demuxer_t *demux, demux_stream_t *ds) {
+ demux_packet_t *pack;
+ int len;
+ demux->filepos = stream_tell(demux->stream);
+ pack = new_demux_packet(STREAM_BUFFER_SIZE);
+ len = stream_read(demux->stream, pack->buffer, STREAM_BUFFER_SIZE);
+ if (len <= 0)
+ {
+ free_demux_packet(pack);
+ return 0;
+ }
+ {
+ register uint32_t state = (uint32_t)demux->priv;
+ register int pos = -len;
+ unsigned char *buf = &pack->buffer[len];
+ do {
+ state = state << 8 | buf[pos];
+ if (unlikely((state | 3) == 0x1bf))
+ pos = find_end(&buf, pos, demux->stream);
+ } while (++pos < 0);
+ demux->priv = (void *)state;
+ len = buf - pack->buffer;
+ }
+ if (len < STREAM_BUFFER_SIZE)
+ resize_demux_packet(pack, len);
+ ds_add_packet(ds, pack);
+ return 1;
+}
+
+static int demux_mpg_fill_buffer(demuxer_t *demux, demux_stream_t *ds)
+{
+unsigned int head=0;
+int skipped=0;
+int max_packs=256; // 512kbyte
+int ret=0;
+
+// System stream
+do{
+ demux->filepos=stream_tell(demux->stream);
+ //lame workaround: this is needed to show the progress bar when playing dvdnav://
+ //(ths poor guy doesn't know teh length of the stream at startup)
+ demux->movi_end = demux->stream->end_pos;
+ head=stream_read_dword(demux->stream);
+ if((head&0xFFFFFF00)!=0x100){
+ // sync...
+ demux->filepos-=skipped;
+ while(1){
+ int c=stream_read_char(demux->stream);
+ if(c<0) break; //EOF
+ head<<=8;
+ if(head!=0x100){
+ head|=c;
+ if(mp_check_mp3_header(head)) ++num_mp3audio_packets;
+ ++skipped; //++demux->filepos;
+ continue;
+ }
+ head|=c;
+ break;
+ }
+ demux->filepos+=skipped;
+ }
+ if(stream_eof(demux->stream)) break;
+ // sure: head=0x000001XX
+ mp_dbg(MSGT_DEMUX,MSGL_DBG4,"*** head=0x%X\n",head);
+ if(demux->synced==0){
+ if(head==0x1BA) demux->synced=1; //else
+// if(head==0x1BD || (head>=0x1C0 && head<=0x1EF)) demux->synced=3; // PES?
+ } else
+ if(demux->synced==1){
+ if(head==0x1BB || head==0x1BD || (head>=0x1C0 && head<=0x1EF)){
+ demux->synced=2;
+ mp_msg(MSGT_DEMUX,MSGL_V,"system stream synced at 0x%"PRIX64" (%"PRId64")!\n",(int64_t)demux->filepos,(int64_t)demux->filepos);
+ num_elementary_packets100=0; // requires for re-sync!
+ num_elementary_packets101=0; // requires for re-sync!
+ } else demux->synced=0;
+ } // else
+ if(demux->synced>=2){
+ ret=demux_mpg_read_packet(demux,head);
+ if(!ret)
+ if(--max_packs==0){
+ demux->stream->eof=1;
+ mp_tmsg(MSGT_DEMUX,MSGL_ERR,"demux: File doesn't contain the selected audio or video stream.\n");
+ return 0;
+ }
+ if(demux->synced==3) demux->synced=(ret==1)?2:0; // PES detect
+ } else {
+ update_stats(head);
+ if(head>=0x100 && head<0x1B0)
+ mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... elementary video packet found: %03X\n",head);
+ else if((head>=0x1C0 && head<0x1F0) || head==0x1BD)
+ mp_msg(MSGT_DEMUX,MSGL_DBG3,"Opps... PES packet found: %03X\n",head);
+
+ if(((num_elementary_packets100>50 && num_elementary_packets101>50) ||
+ (num_elementary_packetsPES>50)) && skipped>4000000){
+ mp_msg(MSGT_DEMUX,MSGL_V,"sync_mpeg_ps: seems to be ES/PES stream...\n");
+ demux->stream->eof=1;
+ break;
+ }
+ if(num_mp3audio_packets>100 && num_elementary_packets100<10){
+ mp_msg(MSGT_DEMUX,MSGL_V,"sync_mpeg_ps: seems to be MP3 stream...\n");
+ demux->stream->eof=1;
+ break;
+ }
+ }
+} while(ret!=1);
+ mp_dbg(MSGT_DEMUX,MSGL_DBG2,"demux: %d bad bytes skipped\n",skipped);
+ if(demux->stream->eof){
+ mp_msg(MSGT_DEMUX,MSGL_V,"MPEG Stream reached EOF\n");
+ return 0;
+ }
+ return 1;
+}
+
+static void demux_seek_mpg(demuxer_t *demuxer, float rel_seek_secs,
+ float audio_delay, int flags)
+{
+ demux_stream_t *d_audio=demuxer->audio;
+ demux_stream_t *d_video=demuxer->video;
+ sh_audio_t *sh_audio=d_audio->sh;
+ sh_video_t *sh_video=d_video->sh;
+ mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demuxer->priv;
+ int precision = 1;
+ float oldpts = 0;
+ off_t oldpos = demuxer->filepos;
+ float newpts = 0;
+ off_t newpos = (flags & SEEK_ABSOLUTE) ? demuxer->movi_start : oldpos;
+
+ if(mpg_d)
+ oldpts = mpg_d->last_pts;
+ newpts = (flags & SEEK_ABSOLUTE) ? 0.0 : oldpts;
+ //================= seek in MPEG ==========================
+ //calculate the pts to seek to
+ if(flags & SEEK_FACTOR) {
+ if (mpg_d && mpg_d->first_to_final_pts_len > 0.0)
+ newpts += mpg_d->first_to_final_pts_len * rel_seek_secs;
+ else
+ newpts += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) * oldpts / oldpos;
+ } else
+ newpts += rel_seek_secs;
+ if (newpts < 0) newpts = 0;
+
+ if(flags&SEEK_FACTOR){
+ // float seek 0..1
+ newpos+=(demuxer->movi_end-demuxer->movi_start)*rel_seek_secs;
+ } else {
+ // time seek (secs)
+ if (mpg_d && mpg_d->has_valid_timestamps) {
+ if (mpg_d->first_to_final_pts_len > 0.0)
+ newpos += rel_seek_secs * (demuxer->movi_end - demuxer->movi_start) / mpg_d->first_to_final_pts_len;
+ else if (oldpts > 0.0)
+ newpos += rel_seek_secs * (oldpos - demuxer->movi_start) / oldpts;
+ } else if(!sh_video || !sh_video->i_bps) // unspecified or VBR
+ newpos+=2324*75*rel_seek_secs; // 174.3 kbyte/sec
+ else
+ newpos+=sh_video->i_bps*rel_seek_secs;
+ }
+
+ while (1) {
+ if(newpos<demuxer->movi_start){
+ if(demuxer->stream->type!=STREAMTYPE_VCD) demuxer->movi_start=0; // for VCD
+ if(newpos<demuxer->movi_start) newpos=demuxer->movi_start;
+ }
+
+ stream_seek(demuxer->stream,newpos);
+
+ // re-sync video:
+ videobuf_code_len=0; // reset ES stream buffer
+
+ ds_fill_buffer(d_video);
+ if(sh_audio){
+ ds_fill_buffer(d_audio);
+ }
+
+ while(1){
+ int i;
+ if(sh_audio && !d_audio->eof && d_video->pts && d_audio->pts){
+ float a_pts=d_audio->pts;
+ a_pts+=(ds_tell_pts(d_audio)-sh_audio->a_in_buffer_len)/(float)sh_audio->i_bps;
+ if(d_video->pts>a_pts){
+ skip_audio_frame(sh_audio); // sync audio
+ continue;
+ }
+ }
+ if(!sh_video) break;
+ i=sync_video_packet(d_video);
+ if(sh_video->format == mmioFOURCC('W', 'V', 'C', '1')) {
+ if(i==0x10E || i==0x10F) //entry point or sequence header
+ break;
+ } else
+ if(sh_video->format == 0x10000004) { //mpeg4
+ if(i==0x1B6) { //vop (frame) startcode
+ int pos = videobuf_len;
+ if(!read_video_packet(d_video)) break; // EOF
+ if((videobuffer[pos+4] & 0x3F) == 0) break; //I-frame
+ }
+ } else if(sh_video->format == 0x10000005){ //h264
+ if((i & ~0x60) == 0x105) break;
+ } else { //default mpeg1/2
+ if(i==0x1B3 || i==0x1B8) break; // found it!
+ }
+ if(!i || !skip_video_packet(d_video)) break; // EOF?
+ }
+ if(!mpg_d)
+ break;
+ if (!precision || abs(newpts - mpg_d->last_pts) < 0.5 || (mpg_d->last_pts == oldpts)) break;
+ if ((newpos - oldpos) * (mpg_d->last_pts - oldpts) < 0) { // invalid timestamps
+ mpg_d->has_valid_timestamps = 0;
+ break;
+ }
+ precision--;
+ //prepare another seek because we are off by more than 0.5s
+ if(mpg_d) {
+ newpos += (newpts - mpg_d->last_pts) * (newpos - oldpos) / (mpg_d->last_pts - oldpts);
+ demux_flush(demuxer);
+ demuxer->stream->eof=0; // clear eof flag
+ d_video->eof=0;
+ d_audio->eof=0;
+ }
+ }
+}
+
+static int demux_mpg_control(demuxer_t *demuxer, int cmd, void *arg)
+{
+ mpg_demuxer_t *mpg_d=(mpg_demuxer_t*)demuxer->priv;
+
+ switch(cmd) {
+ case DEMUXER_CTRL_GET_TIME_LENGTH:
+ if(stream_control(demuxer->stream, STREAM_CTRL_GET_TIME_LENGTH, arg) != STREAM_UNSUPPORTED) {
+ mp_msg(MSGT_DEMUXER,MSGL_DBG2,"\r\nDEMUX_MPG_CTRL, (%.3f)\r\n", *((double*)arg));
+ return DEMUXER_CTRL_GUESS;
+ }
+ if (mpg_d && mpg_d->has_valid_timestamps) {
+ *((double *)arg)=(double)mpg_d->first_to_final_pts_len;
+ return DEMUXER_CTRL_OK;
+ }
+ return DEMUXER_CTRL_DONTKNOW;
+
+ case DEMUXER_CTRL_GET_PERCENT_POS:
+ if (mpg_d && mpg_d->has_valid_timestamps && mpg_d->first_to_final_pts_len > 0.0) {
+ *((int *)arg)=(int)(100 * (mpg_d->last_pts-mpg_d->first_pts) / mpg_d->first_to_final_pts_len);
+ return DEMUXER_CTRL_OK;
+ }
+ return DEMUXER_CTRL_DONTKNOW;
+
+ case DEMUXER_CTRL_SWITCH_AUDIO:
+ if(! (mpg_d && mpg_d->num_a_streams > 1 && demuxer->audio && demuxer->audio->sh))
+ return DEMUXER_CTRL_NOTIMPL;
+ else {
+ demux_stream_t *d_audio = demuxer->audio;
+ sh_audio_t *sh_audio = d_audio->sh;
+ sh_audio_t *sh_a = sh_audio;
+ int i;
+ if(!sh_audio)
+ return DEMUXER_CTRL_NOTIMPL;
+ if (*((int*)arg) < 0)
+ {
+ for (i = 0; i < mpg_d->num_a_streams; i++) {
+ if (d_audio->id == mpg_d->a_stream_ids[i]) break;
+ }
+ i = (i+1) % mpg_d->num_a_streams;
+ sh_a = (sh_audio_t*)demuxer->a_streams[mpg_d->a_stream_ids[i]];
+ }
+ else {
+ for (i = 0; i < mpg_d->num_a_streams; i++)
+ if (*((int*)arg) == mpg_d->a_stream_ids[i]) break;
+ if (i < mpg_d->num_a_streams)
+ sh_a = (sh_audio_t*)demuxer->a_streams[*((int*)arg)];
+ }
+ if (i < mpg_d->num_a_streams && d_audio->id != mpg_d->a_stream_ids[i]) {
+ d_audio->id = mpg_d->a_stream_ids[i];
+ d_audio->sh = sh_a;
+ ds_free_packs(d_audio);
+ }
+ }
+ *((int*)arg) = demuxer->audio->id;
+ return DEMUXER_CTRL_OK;
+
+ default:
+ return DEMUXER_CTRL_NOTIMPL;
+ }
+}
+
+
+static int demux_mpg_pes_probe(demuxer_t *demuxer) {
+ demuxer->synced = 3;
+ return (demux_mpg_probe(demuxer) == DEMUXER_TYPE_MPEG_PS) ? DEMUXER_TYPE_MPEG_PES : 0;
+}
+
+
+static demuxer_t* demux_mpg_es_open(demuxer_t* demuxer)
+{
+ sh_video_t *sh_video=NULL;
+
+ demuxer->audio->sh = NULL; // ES streams has no audio channel
+ demuxer->video->sh = new_sh_video(demuxer,0); // create dummy video stream header, id=0
+ sh_video=demuxer->video->sh;sh_video->ds=demuxer->video;
+
+ return demuxer;
+}
+
+static demuxer_t *demux_mpg_gxf_open(demuxer_t *demuxer) {
+ demuxer->audio->sh = NULL;
+ demuxer->video->sh = new_sh_video(demuxer,0);
+ ((sh_video_t *)demuxer->video->sh)->ds = demuxer->video;
+ demuxer->priv = (void *) 0xffffffff;
+ return demuxer;
+}
+
+static demuxer_t* demux_mpg_ps_open(demuxer_t* demuxer)
+{
+ sh_audio_t *sh_audio=NULL;
+ sh_video_t *sh_video=NULL;
+
+ sh_video=demuxer->video->sh;sh_video->ds=demuxer->video;
+
+ if(demuxer->audio->id!=-2) {
+ if(!ds_fill_buffer(demuxer->audio)){
+ mp_msg(MSGT_DEMUXER, MSGL_INFO, "MPEG: %s",
+ mp_gtext("No audio stream found -> no sound.\n"));
+ demuxer->audio->sh=NULL;
+ } else {
+ sh_audio=demuxer->audio->sh;sh_audio->ds=demuxer->audio;
+ }
+ }
+
+ if(!sh_video->format && ps_probe > 0) {
+ int head;
+ off_t pos = stream_tell(demuxer->stream);
+
+ clear_stats();
+ do {
+ head=sync_video_packet(demuxer->video);
+ if(!head) break;
+ update_stats(head);
+ skip_video_packet(demuxer->video);
+ } while(stream_tell(demuxer->stream) < pos + ps_probe && !demuxer->stream->eof);
+
+ ds_free_packs(demuxer->video);
+ demuxer->stream->eof=0;
+ stream_seek(demuxer->stream, pos);
+ mp_msg(MSGT_DEMUX,MSGL_INFO,"MPEG packet stats: p100: %d p101: %d p1B6: %d p12x: %d sli: %d a: %d b: %d c: %d idr: %d sps: %d pps: %d\n",
+ num_elementary_packets100, num_elementary_packets101,
+ num_elementary_packets1B6, num_elementary_packets12x,
+ num_h264_slice, num_h264_dpa, num_h264_dpb, num_h264_dpc,
+ num_h264_idr, num_h264_sps, num_h264_pps);
+
+ if(num_elementary_packets1B6>3 && num_elementary_packets12x>=1 &&
+ num_elementary_packets100<=num_elementary_packets12x)
+ sh_video->format = 0x10000004;
+ else if((num_h264_slice>3 || (num_h264_dpa>3 && num_h264_dpb>3 && num_h264_dpc>3)) &&
+ num_h264_sps>=1 && num_h264_pps>=1 && num_h264_idr>=1 &&
+ num_elementary_packets1B6==0)
+ sh_video->format = 0x10000005;
+ else sh_video->format = 0x10000002;
+ }
+
+ return demuxer;
+}
+
+
+const demuxer_desc_t demuxer_desc_mpeg_ps = {
+ "MPEG PS demuxer",
+ "mpegps",
+ "MPEG-PS",
+ "Arpi?",
+ "Mpeg",
+ DEMUXER_TYPE_MPEG_PS,
+ 0, // unsafe autodetect
+ demux_mpg_probe,
+ demux_mpg_fill_buffer,
+ demux_mpg_ps_open,
+ demux_close_mpg,
+ demux_seek_mpg,
+ demux_mpg_control,
+};
+
+
+const demuxer_desc_t demuxer_desc_mpeg_pes = {
+ "MPEG PES demuxer",
+ "mpegpes",
+ "MPEG-PES",
+ "Arpi?",
+ "Mpeg",
+ DEMUXER_TYPE_MPEG_PES,
+ 0, // unsafe autodetect
+ demux_mpg_pes_probe,
+ demux_mpg_fill_buffer,
+ demux_mpg_ps_open,
+ demux_close_mpg,
+ demux_seek_mpg,
+ demux_mpg_control,
+};
+
+
+const demuxer_desc_t demuxer_desc_mpeg_gxf = {
+ "MPEG ES in GXF demuxer",
+ "mpeggxf",
+ "MPEG-ES in GXF",
+ "Reimar Doeffinger",
+ "Mpeg",
+ DEMUXER_TYPE_MPEG_GXF,
+ 0, // hack autodetection
+ NULL,
+ demux_mpg_gxf_fill_buffer,
+ demux_mpg_gxf_open,
+ NULL,
+ NULL,
+ NULL
+};
+
+const demuxer_desc_t demuxer_desc_mpeg_es = {
+ "MPEG ES demuxer",
+ "mpeges",
+ "MPEG-ES",
+ "Arpi?",
+ "Mpeg",
+ DEMUXER_TYPE_MPEG_ES,
+ 0, // hack autodetection
+ NULL,
+ demux_mpg_es_fill_buffer,
+ demux_mpg_es_open,
+ demux_close_mpg,
+ demux_seek_mpg,
+ demux_mpg_control,
+};
+
+
+const demuxer_desc_t demuxer_desc_mpeg4_es = {
+ "MPEG4 ES demuxer",
+ "mpeg4es",
+ "MPEG-ES",
+ "Arpi?",
+ "Mpeg",
+ DEMUXER_TYPE_MPEG4_ES,
+ 0, // hack autodetection
+ NULL,
+ demux_mpg_es_fill_buffer,
+ demux_mpg_es_open,
+ demux_close_mpg,
+ demux_seek_mpg,
+ demux_mpg_control,
+};
+
+
+const demuxer_desc_t demuxer_desc_h264_es = {
+ "H.264 ES demuxer",
+ "h264es",
+ "H264-ES",
+ "Arpi?",
+ "Mpeg",
+ DEMUXER_TYPE_H264_ES,
+ 0, // hack autodetection
+ NULL,
+ demux_mpg_es_fill_buffer,
+ demux_mpg_es_open,
+ demux_close_mpg,
+ demux_seek_mpg,
+ demux_mpg_control,
+};
diff --git a/libmpdemux/demuxer.c b/libmpdemux/demuxer.c
index ce425751f9..2372e10843 100644
--- a/libmpdemux/demuxer.c
+++ b/libmpdemux/demuxer.c
@@ -63,6 +63,12 @@ extern const demuxer_desc_t demuxer_desc_gif;
extern const demuxer_desc_t demuxer_desc_lavf;
extern const demuxer_desc_t demuxer_desc_lavf_preferred;
extern const demuxer_desc_t demuxer_desc_mng;
+extern const demuxer_desc_t demuxer_desc_mpeg_ps;
+extern const demuxer_desc_t demuxer_desc_mpeg_pes;
+extern const demuxer_desc_t demuxer_desc_mpeg_gxf;
+extern const demuxer_desc_t demuxer_desc_mpeg_es;
+extern const demuxer_desc_t demuxer_desc_mpeg4_es;
+extern const demuxer_desc_t demuxer_desc_h264_es;
/* Please do not add any new demuxers here. If you want to implement a new
* demuxer, add it to libavformat, except for wrappers around external
@@ -88,6 +94,12 @@ const demuxer_desc_t *const demuxer_list[] = {
#ifdef CONFIG_MNG
&demuxer_desc_mng,
#endif
+ &demuxer_desc_mpeg_ps,
+ &demuxer_desc_mpeg_pes,
+ &demuxer_desc_mpeg_gxf,
+ &demuxer_desc_mpeg_es,
+ &demuxer_desc_mpeg4_es,
+ &demuxer_desc_h264_es,
/* Please do not add any new demuxers here. If you want to implement a new
* demuxer, add it to libavformat, except for wrappers around external
* libraries and demuxers requiring binary support. */
@@ -685,6 +697,43 @@ int demux_read_data(demux_stream_t *ds, unsigned char *mem, int len)
return bytes;
}
+/**
+ * \brief read data until the given 3-byte pattern is encountered, up to maxlen
+ * \param mem memory to read data into, may be NULL to discard data
+ * \param maxlen maximum number of bytes to read
+ * \param read number of bytes actually read
+ * \param pattern pattern to search for (lowest 8 bits are ignored)
+ * \return whether pattern was found
+ */
+int demux_pattern_3(demux_stream_t *ds, unsigned char *mem, int maxlen,
+ int *read, uint32_t pattern)
+{
+ register uint32_t head = 0xffffff00;
+ register uint32_t pat = pattern & 0xffffff00;
+ int total_len = 0;
+ do {
+ register unsigned char *ds_buf = &ds->buffer[ds->buffer_size];
+ int len = ds->buffer_size - ds->buffer_pos;
+ register long pos = -len;
+ if (unlikely(pos >= 0)) { // buffer is empty
+ ds_fill_buffer(ds);
+ continue;
+ }
+ do {
+ head |= ds_buf[pos];
+ head <<= 8;
+ } while (++pos && head != pat);
+ len += pos;
+ if (total_len + len > maxlen)
+ len = maxlen - total_len;
+ len = demux_read_data(ds, mem ? &mem[total_len] : NULL, len);
+ total_len += len;
+ } while ((head != pat || total_len < 3) && total_len < maxlen && !ds->eof);
+ if (read)
+ *read = total_len;
+ return total_len >= 3 && head == pat;
+}
+
void ds_free_packs(demux_stream_t *ds)
{
demux_packet_t *dp = ds->first;
@@ -938,7 +987,7 @@ struct demuxer *demux_open_withparams(struct MPOpts *opts,
// format, instead of reyling on libav to auto-detect the stream's format
// correctly.
switch (file_format) {
- case DEMUXER_TYPE_MPEG_PS:
+ //case DEMUXER_TYPE_MPEG_PS:
case DEMUXER_TYPE_MPEG_TS:
case DEMUXER_TYPE_Y4M:
case DEMUXER_TYPE_NSV:
diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h
index 2dd2c5a35a..8c04c9dad6 100644
--- a/libmpdemux/demuxer.h
+++ b/libmpdemux/demuxer.h
@@ -55,6 +55,11 @@ enum demuxer_type {
DEMUXER_TYPE_MF,
DEMUXER_TYPE_RAWAUDIO,
DEMUXER_TYPE_RAWVIDEO,
+ DEMUXER_TYPE_MPEG_ES,
+ DEMUXER_TYPE_MPEG4_ES,
+ DEMUXER_TYPE_H264_ES,
+ DEMUXER_TYPE_MPEG_PES,
+ DEMUXER_TYPE_MPEG_GXF,
DEMUXER_TYPE_GIF,
DEMUXER_TYPE_MPEG_TS,
DEMUXER_TYPE_MATROSKA,
@@ -319,6 +324,8 @@ static inline int ds_tell_pts(struct demux_stream *ds)
}
int demux_read_data(struct demux_stream *ds, unsigned char *mem, int len);
+int demux_pattern_3(struct demux_stream *ds, unsigned char *mem, int maxlen,
+ int *read, uint32_t pattern);
#define demux_peekc(ds) ( \
(likely(ds->buffer_pos<ds->buffer_size)) ? ds->buffer[ds->buffer_pos] \
diff --git a/libmpdemux/mp3_hdr.c b/libmpdemux/mp3_hdr.c
new file mode 100644
index 0000000000..a4834f4f81
--- /dev/null
+++ b/libmpdemux/mp3_hdr.c
@@ -0,0 +1,144 @@
+/*
+ * 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 "config.h"
+#include "mp3_hdr.h"
+#include "mp_msg.h"
+
+//----------------------- mp3 audio frame header parser -----------------------
+
+static int tabsel_123[2][3][16] = {
+ { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
+ {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,0},
+ {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,0} },
+
+ { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0},
+ {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0},
+ {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0} }
+};
+
+static long freqs[9] = { 44100, 48000, 32000, // MPEG 1.0
+ 22050, 24000, 16000, // MPEG 2.0
+ 11025, 12000, 8000}; // MPEG 2.5
+
+/*
+ * return frame size or -1 (bad frame)
+ */
+int mp_get_mp3_header(unsigned char* hbuf,int* chans, int* srate, int* spf, int* mpa_layer, int* br){
+ int stereo,ssize,lsf,framesize,padding,bitrate_index,sampling_frequency, divisor;
+ int bitrate;
+ int layer, mult[3] = { 12000, 144000, 144000 };
+ unsigned long newhead =
+ hbuf[0] << 24 |
+ hbuf[1] << 16 |
+ hbuf[2] << 8 |
+ hbuf[3];
+
+// printf("head=0x%08X\n",newhead);
+
+ // head_check:
+ if( (newhead & 0xffe00000) != 0xffe00000 ){
+ mp_msg(MSGT_DEMUXER,MSGL_DBG2,"head_check failed\n");
+ return -1;
+ }
+
+ layer = 4-((newhead>>17)&3);
+ if(layer==4){
+ mp_msg(MSGT_DEMUXER,MSGL_DBG2,"not layer-1/2/3\n");
+ return -1;
+ }
+
+ sampling_frequency = ((newhead>>10)&0x3); // valid: 0..2
+ if(sampling_frequency==3){
+ mp_msg(MSGT_DEMUXER,MSGL_DBG2,"invalid sampling_frequency\n");
+ return -1;
+ }
+
+ if( newhead & ((long)1<<20) ) {
+ // MPEG 1.0 (lsf==0) or MPEG 2.0 (lsf==1)
+ lsf = (newhead & ((long)1<<19)) ? 0x0 : 0x1;
+ sampling_frequency += (lsf*3);
+ } else {
+ // MPEG 2.5
+ lsf = 1;
+ sampling_frequency += 6;
+ }
+
+// crc = ((newhead>>16)&0x1)^0x1;
+ bitrate_index = ((newhead>>12)&0xf); // valid: 1..14
+ padding = ((newhead>>9)&0x1);
+// fr->extension = ((newhead>>8)&0x1);
+// fr->mode = ((newhead>>6)&0x3);
+// fr->mode_ext = ((newhead>>4)&0x3);
+// fr->copyright = ((newhead>>3)&0x1);
+// fr->original = ((newhead>>2)&0x1);
+// fr->emphasis = newhead & 0x3;
+
+ stereo = ( (((newhead>>6)&0x3)) == 3) ? 1 : 2;
+
+// !checked later through tabsel_123[]!
+// if(!bitrate_index || bitrate_index==15){
+// mp_msg(MSGT_DEMUXER,MSGL_DBG2,"Free format not supported.\n");
+// return -1;
+// }
+
+ if(lsf)
+ ssize = (stereo == 1) ? 9 : 17;
+ else
+ ssize = (stereo == 1) ? 17 : 32;
+ if(!((newhead>>16)&0x1)) ssize += 2; // CRC
+
+ bitrate = tabsel_123[lsf][layer-1][bitrate_index];
+ framesize = bitrate * mult[layer-1];
+
+ mp_msg(MSGT_DEMUXER,MSGL_DBG2,"FRAMESIZE: %d, layer: %d, bitrate: %d, mult: %d\n",
+ framesize, layer, tabsel_123[lsf][layer-1][bitrate_index], mult[layer-1]);
+ if(!framesize){
+ mp_msg(MSGT_DEMUXER,MSGL_DBG2,"invalid framesize/bitrate_index\n");
+ return -1;
+ }
+
+ divisor = (layer == 3 ? (freqs[sampling_frequency] << lsf) : freqs[sampling_frequency]);
+ framesize /= divisor;
+ if(layer==1)
+ framesize = (framesize+padding)*4;
+ else
+ framesize += padding;
+
+// if(framesize<=0 || framesize>MAXFRAMESIZE) return FALSE;
+ if(srate) {
+ *srate = freqs[sampling_frequency];
+ if(spf) {
+ if(layer == 1)
+ *spf = 384;
+ else if(layer == 2)
+ *spf = 1152;
+ else if(*srate < 32000)
+ *spf = 576;
+ else
+ *spf = 1152;
+ }
+ }
+ if(mpa_layer) *mpa_layer = layer;
+ if(chans) *chans = stereo;
+ if(br) *br = bitrate;
+
+ return framesize;
+}
diff --git a/libmpdemux/mp3_hdr.h b/libmpdemux/mp3_hdr.h
new file mode 100644
index 0000000000..a9b34ac12c
--- /dev/null
+++ b/libmpdemux/mp3_hdr.h
@@ -0,0 +1,36 @@
+/*
+ * 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_MP3_HDR_H
+#define MPLAYER_MP3_HDR_H
+
+#include <stddef.h>
+
+int mp_get_mp3_header(unsigned char* hbuf,int* chans, int* freq, int* spf, int* mpa_layer, int* br);
+
+#define mp_decode_mp3_header(hbuf) mp_get_mp3_header(hbuf,NULL,NULL,NULL,NULL,NULL)
+
+static inline int mp_check_mp3_header(unsigned int head){
+ unsigned char tmp[4] = {head >> 24, head >> 16, head >> 8, head};
+ if( (head & 0xffe00000) != 0xffe00000 ||
+ (head & 0x00000c00) == 0x00000c00) return 0;
+ if(mp_decode_mp3_header(tmp)<=0) return 0;
+ return 1;
+}
+
+#endif /* MPLAYER_MP3_HDR_H */
diff --git a/libmpdemux/mpeg_hdr.c b/libmpdemux/mpeg_hdr.c
new file mode 100644
index 0000000000..0c368aa7a2
--- /dev/null
+++ b/libmpdemux/mpeg_hdr.c
@@ -0,0 +1,539 @@
+/*
+ * based on libmpeg2/header.c by Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * 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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "mpeg_hdr.h"
+#include "libavutil/attributes.h"
+#include "mp_msg.h"
+
+static float frameratecode2framerate[16] = {
+ 0,
+ // Official mpeg1/2 framerates: (1-8)
+ 24000.0/1001, 24,25,
+ 30000.0/1001, 30,50,
+ 60000.0/1001, 60,
+ // Xing's 15fps: (9)
+ 15,
+ // libmpeg3's "Unofficial economy rates": (10-13)
+ 5,10,12,15,
+ // some invalid ones: (14-15)
+ 0,0
+};
+
+
+int mp_header_process_sequence_header (mp_mpeg_header_t * picture, const unsigned char * buffer)
+{
+ int height;
+
+ if ((buffer[6] & 0x20) != 0x20){
+ fprintf(stderr, "missing marker bit!\n");
+ return 1; /* missing marker_bit */
+ }
+
+ height = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
+
+ picture->display_picture_width = height >> 12;
+ picture->display_picture_height = height & 0xfff;
+
+ picture->aspect_ratio_information = buffer[3] >> 4;
+ picture->frame_rate_code = buffer[3] & 15;
+ picture->fps=frameratecode2framerate[picture->frame_rate_code];
+ picture->bitrate = (buffer[4]<<10)|(buffer[5]<<2)|(buffer[6]>>6);
+ picture->mpeg1 = 1;
+ picture->picture_structure = 3; //FRAME_PICTURE;
+ picture->display_time=100;
+ picture->frame_rate_extension_n = 1;
+ picture->frame_rate_extension_d = 1;
+ return 0;
+}
+
+static int header_process_sequence_extension (mp_mpeg_header_t * picture,
+ unsigned char * buffer)
+{
+ /* check chroma format, size extensions, marker bit */
+
+ if ( ((buffer[1] & 0x06) == 0x00) ||
+ ((buffer[1] & 0x01) != 0x00) || (buffer[2] & 0xe0) ||
+ ((buffer[3] & 0x01) != 0x01) )
+ return 1;
+
+ picture->progressive_sequence = (buffer[1] >> 3) & 1;
+ picture->frame_rate_extension_n = ((buffer[5] >> 5) & 3) + 1;
+ picture->frame_rate_extension_d = (buffer[5] & 0x1f) + 1;
+
+ picture->mpeg1 = 0;
+ return 0;
+}
+
+static int header_process_picture_coding_extension (mp_mpeg_header_t * picture, unsigned char * buffer)
+{
+ picture->picture_structure = buffer[2] & 3;
+ picture->top_field_first = buffer[3] >> 7;
+ picture->repeat_first_field = (buffer[3] >> 1) & 1;
+ picture->progressive_frame = buffer[4] >> 7;
+
+ // repeat_first implementation by A'rpi/ESP-team, based on libmpeg3:
+ picture->display_time=100;
+ if(picture->repeat_first_field){
+ if(picture->progressive_sequence){
+ if(picture->top_field_first)
+ picture->display_time+=200;
+ else
+ picture->display_time+=100;
+ } else
+ if(picture->progressive_frame){
+ picture->display_time+=50;
+ }
+ }
+ //temopral hack. We calc time on every field, so if we have 2 fields
+ // interlaced we'll end with double time for 1 frame
+ if( picture->picture_structure!=3 ) picture->display_time/=2;
+ return 0;
+}
+
+int mp_header_process_extension (mp_mpeg_header_t * picture, unsigned char * buffer)
+{
+ switch (buffer[0] & 0xf0) {
+ case 0x10: /* sequence extension */
+ return header_process_sequence_extension (picture, buffer);
+ case 0x80: /* picture coding extension */
+ return header_process_picture_coding_extension (picture, buffer);
+ }
+ return 0;
+}
+
+float mpeg12_aspect_info(mp_mpeg_header_t *picture)
+{
+ float aspect = 0.0;
+
+ switch(picture->aspect_ratio_information) {
+ case 2: // PAL/NTSC SVCD/DVD 4:3
+ case 8: // PAL VCD 4:3
+ case 12: // NTSC VCD 4:3
+ aspect=4.0/3.0;
+ break;
+ case 3: // PAL/NTSC Widescreen SVCD/DVD 16:9
+ case 6: // (PAL?)/NTSC Widescreen SVCD 16:9
+ aspect=16.0/9.0;
+ break;
+ case 4: // according to ISO-138182-2 Table 6.3
+ aspect=2.21;
+ break;
+ case 1: // VGA 1:1 - do not prescale
+ case 9: // Movie Type ??? / 640x480
+ aspect=0.0;
+ break;
+ default:
+ mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Detected unknown aspect_ratio_information in mpeg sequence header.\n"
+ "Please report the aspect value (%i) along with the movie type (VGA,PAL,NTSC,"
+ "SECAM) and the movie resolution (720x576,352x240,480x480,...) to the MPlayer"
+ " developers, so that we can add support for it!\nAssuming 1:1 aspect for now.\n",
+ picture->aspect_ratio_information);
+ }
+
+ return aspect;
+}
+
+//MPEG4 HEADERS
+unsigned char mp_getbits(unsigned char *buffer, unsigned int from, unsigned char len)
+{
+ unsigned int n;
+ unsigned char m, u, l, y;
+
+ n = from / 8;
+ m = from % 8;
+ u = 8 - m;
+ l = (len > u ? len - u : 0);
+
+ y = (buffer[n] << m);
+ if(8 > len)
+ y >>= (8-len);
+ if(l)
+ y |= (buffer[n+1] >> (8-l));
+
+ //fprintf(stderr, "GETBITS(%d -> %d): bytes=0x%x 0x%x, n=%d, m=%d, l=%d, u=%d, Y=%d\n",
+ // from, (int) len, (int) buffer[n],(int) buffer[n+1], n, (int) m, (int) l, (int) u, (int) y);
+ return y;
+}
+
+static inline unsigned int mp_getbits16(unsigned char *buffer, unsigned int from, unsigned char len)
+{
+ if(len > 8)
+ return (mp_getbits(buffer, from, len - 8) << 8) | mp_getbits(buffer, from + len - 8, 8);
+ else
+ return mp_getbits(buffer, from, len);
+}
+
+#define getbits mp_getbits
+#define getbits16 mp_getbits16
+
+static int read_timeinc(mp_mpeg_header_t * picture, unsigned char * buffer, int n)
+{
+ if(picture->timeinc_bits > 8) {
+ picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits - 8) << 8;
+ n += picture->timeinc_bits - 8;
+ picture->timeinc_unit |= getbits(buffer, n, 8);
+ n += 8;
+ } else {
+ picture->timeinc_unit = getbits(buffer, n, picture->timeinc_bits);
+ n += picture->timeinc_bits;
+ }
+ //fprintf(stderr, "TIMEINC2: %d, bits: %d\n", picture->timeinc_unit, picture->timeinc_bits);
+ return n;
+}
+
+int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer)
+{
+ unsigned int n, aspect=0, aspectw av_unused=0, aspecth av_unused=0, x=1, v;
+
+ //begins with 0x0000012x
+ picture->fps = 0;
+ picture->timeinc_bits = picture->timeinc_resolution = picture->timeinc_unit = 0;
+ n = 9;
+ if(getbits(buffer, n, 1))
+ n += 7;
+ n++;
+ aspect=getbits(buffer, n, 4);
+ n += 4;
+ if(aspect == 0x0f) {
+ aspectw = getbits(buffer, n, 8);
+ n += 8;
+ aspecth = getbits(buffer, n, 8);
+ n += 8;
+ }
+
+ if(getbits(buffer, n, 1)) {
+ n += 4;
+ if(getbits(buffer, n, 1))
+ n += 79;
+ n++;
+ } else n++;
+
+ n+=3;
+
+ picture->timeinc_resolution = getbits(buffer, n, 8) << 8;
+ n += 8;
+ picture->timeinc_resolution |= getbits(buffer, n, 8);
+ n += 8;
+
+ picture->timeinc_bits = 0;
+ v = picture->timeinc_resolution - 1;
+ while(v && (x<16)) {
+ v>>=1;
+ picture->timeinc_bits++;
+ }
+ picture->timeinc_bits = (picture->timeinc_bits > 1 ? picture->timeinc_bits : 1);
+
+ n++; //marker bit
+
+ if(getbits(buffer, n++, 1)) { //fixed_vop_timeinc
+ n += read_timeinc(picture, buffer, n);
+
+ if(picture->timeinc_unit)
+ picture->fps = (float) picture->timeinc_resolution / (float) picture->timeinc_unit;
+ }
+
+ n++; //marker bit
+ picture->display_picture_width = getbits16(buffer, n, 13);
+ n += 13;
+ n++; //marker bit
+ picture->display_picture_height = getbits16(buffer, n, 13);
+ n += 13;
+
+ //fprintf(stderr, "ASPECT: %d, PARW=%d, PARH=%d, TIMEINCRESOLUTION: %d, FIXED_TIMEINC: %d (number of bits: %d), FPS: %u\n",
+ // aspect, aspectw, aspecth, picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_bits, picture->fps);
+
+ return 0;
+}
+
+void mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer)
+{
+ int n;
+ n = 0;
+ picture->picture_type = getbits(buffer, n, 2);
+ n += 2;
+ while(getbits(buffer, n, 1))
+ n++;
+ n++;
+ getbits(buffer, n, 1);
+ n++;
+ n += read_timeinc(picture, buffer, n);
+}
+
+#define min(a, b) ((a) <= (b) ? (a) : (b))
+
+static unsigned int read_golomb(unsigned char *buffer, unsigned int *init)
+{
+ unsigned int x, v = 0, v2 = 0, m, len = 0, n = *init;
+
+ while(getbits(buffer, n++, 1) == 0)
+ len++;
+
+ x = len + n;
+ while(n < x)
+ {
+ m = min(x - n, 8);
+ v |= getbits(buffer, n, m);
+ n += m;
+ if(x - n > 8)
+ v <<= 8;
+ }
+
+ v2 = 1;
+ for(n = 0; n < len; n++)
+ v2 <<= 1;
+ v2 = (v2 - 1) + v;
+
+ //fprintf(stderr, "READ_GOLOMB(%u), V=2^%u + %u-1 = %u\n", *init, len, v, v2);
+ *init = x;
+ return v2;
+}
+
+inline static int read_golomb_s(unsigned char *buffer, unsigned int *init)
+{
+ unsigned int v = read_golomb(buffer, init);
+ return (v & 1) ? ((v + 1) >> 1) : -(v >> 1);
+}
+
+static int h264_parse_vui(mp_mpeg_header_t * picture, unsigned char * buf, unsigned int n)
+{
+ unsigned int overscan, vsp_color, chroma, timing, fixed_fps;
+
+ if(getbits(buf, n++, 1))
+ {
+ picture->aspect_ratio_information = getbits(buf, n, 8);
+ n += 8;
+ if(picture->aspect_ratio_information == 255)
+ {
+ picture->display_picture_width = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8);
+ n += 16;
+
+ picture->display_picture_height = (getbits(buf, n, 8) << 8) | getbits(buf, n + 8, 8);
+ n += 16;
+ }
+ }
+
+ if((overscan=getbits(buf, n++, 1)))
+ n++;
+ if((vsp_color=getbits(buf, n++, 1)))
+ {
+ n += 4;
+ if(getbits(buf, n++, 1))
+ n += 24;
+ }
+ if((chroma=getbits(buf, n++, 1)))
+ {
+ read_golomb(buf, &n);
+ read_golomb(buf, &n);
+ }
+ if((timing=getbits(buf, n++, 1)))
+ {
+ picture->timeinc_unit = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8);
+ n += 32;
+
+ picture->timeinc_resolution = (getbits(buf, n, 8) << 24) | (getbits(buf, n+8, 8) << 16) | (getbits(buf, n+16, 8) << 8) | getbits(buf, n+24, 8);
+ n += 32;
+
+ fixed_fps = getbits(buf, n, 1);
+
+ if(picture->timeinc_unit > 0 && picture->timeinc_resolution > 0)
+ picture->fps = (float) picture->timeinc_resolution / (float) picture->timeinc_unit;
+ if(fixed_fps)
+ picture->fps /= 2;
+ }
+
+ //fprintf(stderr, "H264_PARSE_VUI, OVESCAN=%u, VSP_COLOR=%u, CHROMA=%u, TIMING=%u, DISPW=%u, DISPH=%u, TIMERES=%u, TIMEINC=%u, FIXED_FPS=%u\n", overscan, vsp_color, chroma, timing, picture->display_picture_width, picture->display_picture_height,
+ // picture->timeinc_resolution, picture->timeinc_unit, picture->timeinc_unit, fixed_fps);
+
+ return n;
+}
+
+static int mp_unescape03(unsigned char *buf, int len)
+{
+ unsigned char *dest;
+ int i, j, skip;
+
+ dest = malloc(len);
+ if(! dest)
+ return 0;
+
+ j = i = skip = 0;
+ while(i <= len-3)
+ {
+ if(buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 3)
+ {
+ dest[j] = dest[j+1] = 0;
+ j += 2;
+ i += 3;
+ skip++;
+ }
+ else
+ {
+ dest[j] = buf[i];
+ j++;
+ i++;
+ }
+ }
+ dest[j] = buf[len-2];
+ dest[j+1] = buf[len-1];
+ len -= skip;
+ memcpy(buf, dest, len);
+ free(dest);
+
+ return len;
+}
+
+int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len)
+{
+ unsigned int n = 0, v, i, k, mbh;
+ int frame_mbs_only;
+
+ len = mp_unescape03(buf, len);
+
+ picture->fps = picture->timeinc_unit = picture->timeinc_resolution = 0;
+ n = 24;
+ read_golomb(buf, &n);
+ if(buf[0] >= 100){
+ if(read_golomb(buf, &n) == 3)
+ n++;
+ read_golomb(buf, &n);
+ read_golomb(buf, &n);
+ n++;
+ if(getbits(buf, n++, 1)){
+ for(i = 0; i < 8; i++)
+ { // scaling list is skipped for now
+ if(getbits(buf, n++, 1))
+ {
+ v = 8;
+ for(k = (i < 6 ? 16 : 64); k && v; k--)
+ v = (v + read_golomb_s(buf, &n)) & 255;
+ }
+ }
+ }
+ }
+ read_golomb(buf, &n);
+ v = read_golomb(buf, &n);
+ if(v == 0)
+ read_golomb(buf, &n);
+ else if(v == 1)
+ {
+ getbits(buf, n++, 1);
+ read_golomb(buf, &n);
+ read_golomb(buf, &n);
+ v = read_golomb(buf, &n);
+ for(i = 0; i < v; i++)
+ read_golomb(buf, &n);
+ }
+ read_golomb(buf, &n);
+ getbits(buf, n++, 1);
+ picture->display_picture_width = 16 *(read_golomb(buf, &n)+1);
+ mbh = read_golomb(buf, &n)+1;
+ frame_mbs_only = getbits(buf, n++, 1);
+ picture->display_picture_height = 16 * (2 - frame_mbs_only) * mbh;
+ if(!frame_mbs_only)
+ getbits(buf, n++, 1);
+ getbits(buf, n++, 1);
+ if(getbits(buf, n++, 1))
+ {
+ read_golomb(buf, &n);
+ read_golomb(buf, &n);
+ read_golomb(buf, &n);
+ read_golomb(buf, &n);
+ }
+ if(getbits(buf, n++, 1))
+ n = h264_parse_vui(picture, buf, n);
+
+ return n;
+}
+
+int mp_vc1_decode_sequence_header(mp_mpeg_header_t * picture, unsigned char * buf, int len)
+{
+ int n, x;
+
+ len = mp_unescape03(buf, len);
+
+ picture->display_picture_width = picture->display_picture_height = 0;
+ picture->fps = 0;
+ n = 0;
+ x = getbits(buf, n, 2);
+ n += 2;
+ if(x != 3) //not advanced profile
+ return 0;
+
+ getbits16(buf, n, 14);
+ n += 14;
+ picture->display_picture_width = getbits16(buf, n, 12) * 2 + 2;
+ n += 12;
+ picture->display_picture_height = getbits16(buf, n, 12) * 2 + 2;
+ n += 12;
+ getbits(buf, n, 6);
+ n += 6;
+ x = getbits(buf, n, 1);
+ n += 1;
+ if(x) //display info
+ {
+ getbits16(buf, n, 14);
+ n += 14;
+ getbits16(buf, n, 14);
+ n += 14;
+ if(getbits(buf, n++, 1)) //aspect ratio
+ {
+ x = getbits(buf, n, 4);
+ n += 4;
+ if(x == 15)
+ {
+ getbits16(buf, n, 16);
+ n += 16;
+ }
+ }
+
+ if(getbits(buf, n++, 1)) //framerates
+ {
+ int frexp=0, frnum=0, frden=0;
+
+ if(getbits(buf, n++, 1))
+ {
+ frexp = getbits16(buf, n, 16);
+ n += 16;
+ picture->fps = (double) (frexp+1) / 32.0;
+ }
+ else
+ {
+ float frates[] = {0, 24000, 25000, 30000, 50000, 60000, 48000, 72000, 0};
+ float frdivs[] = {0, 1000, 1001, 0};
+
+ frnum = getbits(buf, n, 8);
+ n += 8;
+ frden = getbits(buf, n, 4);
+ n += 4;
+ if((frden == 1 || frden == 2) && (frnum < 8))
+ picture->fps = frates[frnum] / frdivs[frden];
+ }
+ }
+ }
+
+ //free(dest);
+ return 1;
+}
diff --git a/libmpdemux/mpeg_hdr.h b/libmpdemux/mpeg_hdr.h
new file mode 100644
index 0000000000..ccd84bcdb0
--- /dev/null
+++ b/libmpdemux/mpeg_hdr.h
@@ -0,0 +1,55 @@
+/*
+ * 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_MPEG_HDR_H
+#define MPLAYER_MPEG_HDR_H
+
+typedef struct {
+ // video info:
+ int mpeg1; // 0=mpeg2 1=mpeg1
+ int display_picture_width;
+ int display_picture_height;
+ int aspect_ratio_information;
+ int frame_rate_code;
+ float fps;
+ int frame_rate_extension_n;
+ int frame_rate_extension_d;
+ int bitrate; // 0x3FFFF==VBR
+ // timing:
+ int picture_structure;
+ int progressive_sequence;
+ int repeat_first_field;
+ int progressive_frame;
+ int top_field_first;
+ int display_time; // secs*100
+ //the following are for mpeg4
+ unsigned int timeinc_resolution, timeinc_bits, timeinc_unit;
+ int picture_type;
+} mp_mpeg_header_t;
+
+int mp_header_process_sequence_header (mp_mpeg_header_t * picture, const unsigned char * buffer);
+int mp_header_process_extension (mp_mpeg_header_t * picture, unsigned char * buffer);
+float mpeg12_aspect_info(mp_mpeg_header_t *picture);
+int mp4_header_process_vol(mp_mpeg_header_t * picture, unsigned char * buffer);
+void mp4_header_process_vop(mp_mpeg_header_t * picture, unsigned char * buffer);
+int h264_parse_sps(mp_mpeg_header_t * picture, unsigned char * buf, int len);
+int mp_vc1_decode_sequence_header(mp_mpeg_header_t * picture, unsigned char * buf, int len);
+
+unsigned char mp_getbits(unsigned char *buffer, unsigned int from, unsigned char len);
+
+#endif /* MPLAYER_MPEG_HDR_H */
diff --git a/libmpdemux/parse_es.c b/libmpdemux/parse_es.c
new file mode 100644
index 0000000000..05507a495a
--- /dev/null
+++ b/libmpdemux/parse_es.c
@@ -0,0 +1,158 @@
+/*
+ * MPEG-ES video parser
+ *
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "mp_msg.h"
+
+#include "stream/stream.h"
+#include "demuxer.h"
+#include "parse_es.h"
+
+//static unsigned char videobuffer[MAX_VIDEO_PACKET_SIZE];
+unsigned char* videobuffer=NULL;
+int videobuf_len=0;
+int next_nal = -1;
+///! legacy variable, 4 if stream is synced, 0 if not
+int videobuf_code_len=0;
+
+#define MAX_SYNCLEN (10 * 1024 * 1024)
+// sync video stream, and returns next packet code
+int sync_video_packet(demux_stream_t *ds){
+ if (!videobuf_code_len) {
+ int skipped=0;
+ if (!demux_pattern_3(ds, NULL, MAX_SYNCLEN, &skipped, 0x100)) {
+ if (skipped == MAX_SYNCLEN)
+ mp_msg(MSGT_DEMUXER, MSGL_ERR, "parse_es: could not sync video stream!\n");
+ goto eof_out;
+ }
+ next_nal = demux_getc(ds);
+ if (next_nal < 0)
+ goto eof_out;
+ videobuf_code_len = 4;
+ if(skipped) mp_dbg(MSGT_PARSEES,MSGL_DBG2,"videobuf: %d bytes skipped (next: 0x1%02X)\n",skipped,next_nal);
+ }
+ return 0x100|next_nal;
+
+eof_out:
+ next_nal = -1;
+ videobuf_code_len = 0;
+ return 0;
+}
+
+// return: packet length
+int read_video_packet(demux_stream_t *ds){
+int packet_start;
+ int res, read;
+
+ if (VIDEOBUFFER_SIZE - videobuf_len < 5)
+ return 0;
+ // SYNC STREAM
+// if(!sync_video_packet(ds)) return 0; // cannot sync (EOF)
+
+ // COPY STARTCODE:
+ packet_start=videobuf_len;
+ videobuffer[videobuf_len+0]=0;
+ videobuffer[videobuf_len+1]=0;
+ videobuffer[videobuf_len+2]=1;
+ videobuffer[videobuf_len+3]=next_nal;
+ videobuf_len+=4;
+
+ // READ PACKET:
+ res = demux_pattern_3(ds, &videobuffer[videobuf_len],
+ VIDEOBUFFER_SIZE - videobuf_len, &read, 0x100);
+ videobuf_len += read;
+ if (!res)
+ goto eof_out;
+
+ videobuf_len-=3;
+
+ mp_dbg(MSGT_PARSEES,MSGL_DBG2,"videobuf: packet 0x1%02X len=%d (total=%d)\n",videobuffer[packet_start+3],videobuf_len-packet_start,videobuf_len);
+
+ // Save next packet code:
+ next_nal = demux_getc(ds);
+ if (next_nal < 0)
+ goto eof_out;
+ videobuf_code_len=4;
+
+ return videobuf_len-packet_start;
+
+eof_out:
+ next_nal = -1;
+ videobuf_code_len = 0;
+ return videobuf_len - packet_start;
+}
+
+// return: next packet code
+int skip_video_packet(demux_stream_t *ds){
+
+ // SYNC STREAM
+// if(!sync_video_packet(ds)) return 0; // cannot sync (EOF)
+
+ videobuf_code_len=0; // force resync
+
+ // SYNC AGAIN:
+ return sync_video_packet(ds);
+}
+
+/* stripped down version of a52_syncinfo() from liba52
+ * copyright belongs to Michel Lespinasse <walken@zoy.org>
+ * and Aaron Holtzman <aholtzma@ess.engr.uvic.ca> */
+int mp_a52_framesize(uint8_t * buf, int *srate)
+{
+ int rate[] = { 32, 40, 48, 56, 64, 80, 96, 112,
+ 128, 160, 192, 224, 256, 320, 384, 448,
+ 512, 576, 640
+ };
+ uint8_t halfrate[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
+ int frmsizecod, bitrate, half;
+
+ if ((buf[0] != 0x0b) || (buf[1] != 0x77)) /* syncword */
+ return 0;
+
+ if (buf[5] >= 0x60) /* bsid >= 12 */
+ return 0;
+
+ half = halfrate[buf[5] >> 3];
+
+ frmsizecod = buf[4] & 63;
+ if (frmsizecod >= 38)
+ return 0;
+
+ bitrate = rate[frmsizecod >> 1];
+
+ switch (buf[4] & 0xc0) {
+ case 0: /* 48 KHz */
+ *srate = 48000 >> half;
+ return 4 * bitrate;
+ case 0x40: /* 44.1 KHz */
+ *srate = 44100 >> half;
+ return 2 * (320 * bitrate / 147 + (frmsizecod & 1));
+ case 0x80: /* 32 KHz */
+ *srate = 32000 >> half;
+ return 6 * bitrate;
+ }
+
+ return 0;
+}
diff --git a/libmpdemux/parse_es.h b/libmpdemux/parse_es.h
new file mode 100644
index 0000000000..ed76593e50
--- /dev/null
+++ b/libmpdemux/parse_es.h
@@ -0,0 +1,45 @@
+/*
+ * 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_PARSE_ES_H
+#define MPLAYER_PARSE_ES_H
+
+#include <stdint.h>
+
+#include "demuxer.h"
+
+#define MAX_VIDEO_PACKET_SIZE (224*1024+4)
+#define VIDEOBUFFER_SIZE 0x100000
+
+extern unsigned char* videobuffer;
+extern int videobuf_len;
+extern unsigned char videobuf_code[4];
+extern int videobuf_code_len;
+
+// sync video stream, and returns next packet code
+int sync_video_packet(demux_stream_t *ds);
+
+// return: packet length
+int read_video_packet(demux_stream_t *ds);
+
+// return: next packet code
+int skip_video_packet(demux_stream_t *ds);
+
+int mp_a52_framesize(uint8_t *buf, int *srate);
+
+#endif /* MPLAYER_PARSE_ES_H */
diff --git a/libmpdemux/video.c b/libmpdemux/video.c
index ba1e9964ab..11e512f119 100644
--- a/libmpdemux/video.c
+++ b/libmpdemux/video.c
@@ -25,21 +25,75 @@
#include <string.h>
#include <unistd.h>
+#include <libavutil/mem.h>
+
#include "mp_msg.h"
#include "stream/stream.h"
#include "demuxer.h"
-#ifdef DEMUX_TY_OSD
-#include "demux_ty_osd.h"
-#endif
#include "stheader.h"
+#include "parse_es.h"
+#include "mpeg_hdr.h"
+
+/* sub_cc (closed captions)*/
+//#include "sub/sub_cc.h"
/* biCompression constant */
#define BI_RGB 0L
+static mp_mpeg_header_t picture;
+
+static int telecine=0;
+static float telecine_cnt=-2.5;
+
+typedef enum {
+ VIDEO_MPEG12,
+ VIDEO_MPEG4,
+ VIDEO_H264,
+ VIDEO_VC1,
+ VIDEO_OTHER
+} video_codec_t;
+
+static video_codec_t find_video_codec(sh_video_t *sh_video)
+{
+ demux_stream_t *d_video=sh_video->ds;
+ int fmt = d_video->demuxer->file_format;
+
+ if(
+ (fmt == DEMUXER_TYPE_MPEG_ES) ||
+ (fmt == DEMUXER_TYPE_MPEG_GXF) ||
+ (fmt == DEMUXER_TYPE_MPEG_PES) ||
+ (
+ (fmt == DEMUXER_TYPE_MPEG_PS || fmt == DEMUXER_TYPE_MPEG_TS) &&
+ ((! sh_video->format) || (sh_video->format==0x10000001) || (sh_video->format==0x10000002))
+ )
+ )
+ return VIDEO_MPEG12;
+ else if((fmt == DEMUXER_TYPE_MPEG4_ES) ||
+ ((fmt == DEMUXER_TYPE_MPEG_TS) && (sh_video->format==0x10000004)) ||
+ ((fmt == DEMUXER_TYPE_MPEG_PS) && (sh_video->format==0x10000004))
+ )
+ return VIDEO_MPEG4;
+ else if((fmt == DEMUXER_TYPE_H264_ES) ||
+ ((fmt == DEMUXER_TYPE_MPEG_TS) && (sh_video->format==0x10000005)) ||
+ ((fmt == DEMUXER_TYPE_MPEG_PS) && (sh_video->format==0x10000005))
+ )
+ return VIDEO_H264;
+ else if((fmt == DEMUXER_TYPE_MPEG_PS || fmt == DEMUXER_TYPE_MPEG_TS) &&
+ (sh_video->format==mmioFOURCC('W', 'V', 'C', '1')))
+ return VIDEO_VC1;
+ else if (fmt == DEMUXER_TYPE_ASF && sh_video->bih && sh_video->bih->biCompression == mmioFOURCC('D', 'V', 'R', ' '))
+ return VIDEO_MPEG12;
+ else
+ return VIDEO_OTHER;
+}
+
int video_read_properties(sh_video_t *sh_video){
demux_stream_t *d_video=sh_video->ds;
-
+video_codec_t video_codec = find_video_codec(sh_video);
+// Determine image properties:
+switch(video_codec){
+ case VIDEO_OTHER: {
if((d_video->demuxer->file_format == DEMUXER_TYPE_ASF) || (d_video->demuxer->file_format == DEMUXER_TYPE_AVI)) {
// display info:
// in case no strf chunk has been seen in avi, we have no bitmap header
@@ -48,22 +102,457 @@ demux_stream_t *d_video=sh_video->ds;
sh_video->disp_w=sh_video->bih->biWidth;
sh_video->disp_h=abs(sh_video->bih->biHeight);
}
+ break;
+ }
+ case VIDEO_MPEG4: {
+ int pos = 0, vop_cnt=0, units[3];
+ videobuf_len=0; videobuf_code_len=0;
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for Video Object Start code... ");
+ while(1){
+ int i=sync_video_packet(d_video);
+ if(i<=0x11F) break; // found it!
+ if(!i || !skip_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
+ return 0;
+ }
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
+ if(!videobuffer) {
+ videobuffer = av_malloc(VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE);
+ if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE);
+ else {
+ mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n");
+ return 0;
+ }
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for Video Object Layer Start code... ");
+ while(1){
+ int i=sync_video_packet(d_video);
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"M4V: 0x%X\n",i);
+ if(i>=0x120 && i<=0x12F) break; // found it!
+ if(!i || !read_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
+ return 0;
+ }
+ }
+ pos = videobuf_len+4;
+ if(!read_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Layer Header\n");
+ return 0;
+ }
+ mp4_header_process_vol(&picture, &(videobuffer[pos]));
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"OK! FPS SEEMS TO BE %.3f\nSearching for Video Object Plane Start code... ", sh_video->fps);
+ mp4_init:
+ while(1){
+ int i=sync_video_packet(d_video);
+ if(i==0x1B6) break; // found it!
+ if(!i || !read_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
+ return 0;
+ }
+ }
+ pos = videobuf_len+4;
+ if(!read_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read Video Object Plane Header\n");
+ return 0;
+ }
+ mp4_header_process_vop(&picture, &(videobuffer[pos]));
+ sh_video->disp_w = picture.display_picture_width;
+ sh_video->disp_h = picture.display_picture_height;
+ units[vop_cnt] = picture.timeinc_unit;
+ vop_cnt++;
+ //mp_msg(MSGT_DECVIDEO,MSGL_V, "TYPE: %d, unit: %d\n", picture.picture_type, picture.timeinc_unit);
+ if(!picture.fps) {
+ int i, mn, md, mx, diff;
+ if(vop_cnt < 3)
+ goto mp4_init;
+
+ i=0;
+ mn = mx = units[0];
+ for(i=0; i<3; i++) {
+ if(units[i] < mn)
+ mn = units[i];
+ if(units[i] > mx)
+ mx = units[i];
+ }
+ md = mn;
+ for(i=0; i<3; i++) {
+ if((units[i] > mn) && (units[i] < mx))
+ md = units[i];
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_V, "MIN: %d, mid: %d, max: %d\n", mn, md, mx);
+ if(mx - md > md - mn)
+ diff = md - mn;
+ else
+ diff = mx - md;
+ if(diff > 0){
+ picture.fps = ((float)picture.timeinc_resolution) / diff;
+ mp_msg(MSGT_DECVIDEO,MSGL_V, "FPS seems to be: %f, resolution: %d, delta_units: %d\n", picture.fps, picture.timeinc_resolution, diff);
+ }
+ }
+ if(picture.fps) {
+ sh_video->fps=picture.fps;
+ sh_video->frametime=1.0/picture.fps;
+ mp_msg(MSGT_DECVIDEO,MSGL_INFO, "FPS seems to be: %f\n", picture.fps);
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
+ sh_video->format=0x10000004;
+ break;
+ }
+ case VIDEO_H264: {
+ int pos = 0;
+ videobuf_len=0; videobuf_code_len=0;
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for sequence parameter set... ");
+ while(1){
+ int i=sync_video_packet(d_video);
+ if((i&~0x60) == 0x107 && i != 0x107) break; // found it!
+ if(!i || !skip_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
+ return 0;
+ }
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
+ if(!videobuffer) {
+ videobuffer = av_malloc(VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE);
+ if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE);
+ else {
+ mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n");
+ return 0;
+ }
+ }
+ pos = videobuf_len+4;
+ if(!read_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Can't read sequence parameter set\n");
+ return 0;
+ }
+ h264_parse_sps(&picture, &(videobuffer[pos]), videobuf_len - pos);
+ sh_video->disp_w=picture.display_picture_width;
+ sh_video->disp_h=picture.display_picture_height;
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for picture parameter set... ");
+ while(1){
+ int i=sync_video_packet(d_video);
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"H264: 0x%X\n",i);
+ if((i&~0x60) == 0x108 && i != 0x108) break; // found it!
+ if(!i || !read_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
+ return 0;
+ }
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\nSearching for Slice... ");
+ while(1){
+ int i=sync_video_packet(d_video);
+ if((i&~0x60) == 0x101 || (i&~0x60) == 0x102 || (i&~0x60) == 0x105) break; // found it!
+ if(!i || !read_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
+ return 0;
+ }
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
+ sh_video->format=0x10000005;
+ if(picture.fps) {
+ sh_video->fps=picture.fps;
+ sh_video->frametime=1.0/picture.fps;
+ mp_msg(MSGT_DECVIDEO,MSGL_INFO, "FPS seems to be: %f\n", picture.fps);
+ }
+ break;
+ }
+ case VIDEO_MPEG12: {
+ if (d_video->demuxer->file_format == DEMUXER_TYPE_ASF) { // DVR-MS
+ if(!sh_video->bih) return 0;
+ sh_video->format=sh_video->bih->biCompression;
+ }
+mpeg_header_parser:
+ // Find sequence_header first:
+ videobuf_len=0; videobuf_code_len=0;
+ telecine=0; telecine_cnt=-2.5;
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"Searching for sequence header... ");
+ while(1){
+ int i=sync_video_packet(d_video);
+ if(i==0x1B3) break; // found it!
+ if(!i || !skip_video_packet(d_video)){
+ if( mp_msg_test(MSGT_DECVIDEO,MSGL_V) ) mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
+ mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"MPEG: FATAL: EOF while searching for sequence header.\n");
+ return 0;
+ }
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"OK!\n");
+ // ========= Read & process sequence header & extension ============
+ if(!videobuffer) {
+ videobuffer = av_malloc(VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE);
+ if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE);
+ else {
+ mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n");
+ return 0;
+ }
+ }
+
+ if(!read_video_packet(d_video)){
+ mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"FATAL: Cannot read sequence header.\n");
+ return 0;
+ }
+ if(mp_header_process_sequence_header (&picture, &videobuffer[4])) {
+ mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"MPEG: bad sequence header\n");
+ goto mpeg_header_parser;
+ }
+ if(sync_video_packet(d_video)==0x1B5){ // next packet is seq. ext.
+ int pos=videobuf_len;
+ if(!read_video_packet(d_video)){
+ mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"FATAL: Cannot read sequence header extension.\n");
+ return 0;
+ }
+ if(mp_header_process_extension (&picture, &videobuffer[pos+4])) {
+ mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"MPEG: bad sequence header extension\n");
+ return 0;
+ }
+ }
+
+ // display info:
+ sh_video->format=picture.mpeg1?0x10000001:0x10000002; // mpeg video
+ sh_video->fps=picture.fps * picture.frame_rate_extension_n / picture.frame_rate_extension_d;
+ if(!sh_video->fps){
+ sh_video->frametime=0;
+ } else {
+ sh_video->frametime=1.0/sh_video->fps;
+ }
+ sh_video->disp_w=picture.display_picture_width;
+ sh_video->disp_h=picture.display_picture_height;
+ // bitrate:
+ if(picture.bitrate!=0x3FFFF) // unspecified/VBR ?
+ sh_video->i_bps=picture.bitrate * 400 / 8;
+ // info:
+ mp_dbg(MSGT_DECVIDEO,MSGL_DBG2,"mpeg bitrate: %d (%X)\n",picture.bitrate,picture.bitrate);
+ mp_msg(MSGT_DECVIDEO,MSGL_INFO,"VIDEO: %s %dx%d (aspect %d) %5.3f fps %5.1f kbps (%4.1f kbyte/s)\n",
+ picture.mpeg1?"MPEG1":"MPEG2",
+ sh_video->disp_w,sh_video->disp_h,
+ picture.aspect_ratio_information,
+ sh_video->fps,
+ sh_video->i_bps * 8 / 1000.0,
+ sh_video->i_bps / 1000.0 );
+ break;
+ }
+ case VIDEO_VC1: {
+ // Find sequence_header:
+ videobuf_len=0;
+ videobuf_code_len=0;
+ mp_msg(MSGT_DECVIDEO,MSGL_INFO,"Searching for VC1 sequence header... ");
+ while(1){
+ int i=sync_video_packet(d_video);
+ if(i==0x10F) break; // found it!
+ if(!i || !skip_video_packet(d_video)){
+ if( mp_msg_test(MSGT_DECVIDEO,MSGL_V) ) mp_msg(MSGT_DECVIDEO,MSGL_V,"NONE :(\n");
+ mp_msg(MSGT_DECVIDEO,MSGL_ERR, "Couldn't find VC-1 sequence header\n");
+ return 0;
+ }
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_INFO,"found\n");
+ if(!videobuffer) {
+ videobuffer = av_malloc(VIDEOBUFFER_SIZE + MP_INPUT_BUFFER_PADDING_SIZE);
+ if (videobuffer) memset(videobuffer+VIDEOBUFFER_SIZE, 0, MP_INPUT_BUFFER_PADDING_SIZE);
+ else {
+ mp_tmsg(MSGT_DECVIDEO,MSGL_ERR,"Cannot allocate shared memory.\n");
+ return 0;
+ }
+ }
+ if(!read_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_ERR, "Couldn't read VC-1 sequence header!\n");
+ return 0;
+ }
+
+ while(1) {
+ int i=sync_video_packet(d_video);
+ if(i==0x10E) break; // found it!
+ if(!i || !skip_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"Couldn't find VC-1 entry point sync-code:(\n");
+ return 0;
+ }
+ }
+ if(!read_video_packet(d_video)){
+ mp_msg(MSGT_DECVIDEO,MSGL_V,"Couldn't read VC-1 entry point sync-code:(\n");
+ return 0;
+ }
+
+ if(mp_vc1_decode_sequence_header(&picture, &videobuffer[4], videobuf_len-4)) {
+ sh_video->bih = calloc(1, sizeof(*sh_video->bih) + videobuf_len);
+ if(sh_video->bih == NULL) {
+ mp_msg(MSGT_DECVIDEO,MSGL_ERR,"Couldn't alloc %zu bytes for VC-1 extradata!\n", sizeof(*sh_video->bih) + videobuf_len);
+ return 0;
+ }
+ sh_video->bih->biSize= sizeof(*sh_video->bih) + videobuf_len;
+ memcpy(sh_video->bih + 1, videobuffer, videobuf_len);
+ sh_video->bih->biCompression = sh_video->format;
+ sh_video->bih->biWidth = sh_video->disp_w = picture.display_picture_width;
+ sh_video->bih->biHeight = sh_video->disp_h = picture.display_picture_height;
+ if(picture.fps > 0) {
+ sh_video->frametime=1.0/picture.fps;
+ sh_video->fps = picture.fps;
+ }
+ mp_msg(MSGT_DECVIDEO,MSGL_INFO,"VIDEO: VC-1 %dx%d, %5.3f fps, header len: %d\n",
+ sh_video->disp_w, sh_video->disp_h, sh_video->fps, videobuf_len);
+ }
+ break;
+ }
+} // switch(file_format)
return 1;
}
+static void process_userdata(const unsigned char* buf,int len){
+ int i;
+ /* if the user data starts with "CC", assume it is a CC info packet */
+ if(len>2 && buf[0]=='C' && buf[1]=='C'){
+// mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"video.c: process_userdata() detected Closed Captions!\n");
+ //subcc_process_data(buf+2,len-2);
+ }
+ if(verbose<2) return;
+ fprintf(stderr, "user_data: len=%3d %02X %02X %02X %02X '",
+ len, buf[0], buf[1], buf[2], buf[3]);
+ for(i=0;i<len;i++)
+// if(buf[i]>=32 && buf[i]<127) fputc(buf[i], stderr);
+ if(buf[i]&0x60) fputc(buf[i]&0x7F, stderr);
+ fprintf(stderr, "'\n");
+}
+
int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char** start,int force_fps){
demux_stream_t *d_video=sh_video->ds;
demuxer_t *demuxer=d_video->demuxer;
float frame_time=1;
float pts1=d_video->pts;
+ float pts=0;
+ float fps;
+ int picture_coding_type=0;
int in_size=0;
+ video_codec_t video_codec = find_video_codec(sh_video);
*start=NULL;
+ if(video_codec == VIDEO_MPEG12){
+ int in_frame=0;
+ //float newfps;
+ //videobuf_len=0;
+ while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){
+ int i=sync_video_packet(d_video);
+ //void* buffer=&videobuffer[videobuf_len+4];
+ int start=videobuf_len+4;
+ if(in_frame){
+ if(i<0x101 || i>=0x1B0){ // not slice code -> end of frame
+ if(!i) return -1; // EOF
+ break;
+ }
+ } else {
+ if(i==0x100){
+ pts=d_video->pts;
+ d_video->pts=0;
+ }
+ if(i>=0x101 && i<0x1B0) in_frame=1; // picture startcode
+ else if(!i) return -1; // EOF
+ }
+ if(!read_video_packet(d_video)) return -1; // EOF
+ // process headers:
+ switch(i){
+ case 0x1B3: mp_header_process_sequence_header (&picture, &videobuffer[start]);break;
+ case 0x1B5: mp_header_process_extension (&picture, &videobuffer[start]);break;
+ case 0x1B2: process_userdata (&videobuffer[start], videobuf_len-start);break;
+ case 0x100: picture_coding_type=(videobuffer[start+1] >> 3) & 7;break;
+ }
+ }
+ fps = picture.fps * picture.frame_rate_extension_n / picture.frame_rate_extension_d;
+
+ *start=videobuffer; in_size=videobuf_len;
+
+ // get mpeg fps:
+ if(sh_video->fps!=fps) if(!force_fps && !telecine){
+ mp_msg(MSGT_CPLAYER,MSGL_WARN,"Warning! FPS changed %5.3f -> %5.3f (%f) [%d] \n",sh_video->fps,fps,sh_video->fps-fps,picture.frame_rate_code);
+ sh_video->fps=fps;
+ sh_video->frametime=1.0/fps;
+ }
+
+ // fix mpeg2 frametime:
+ frame_time=(picture.display_time)*0.01f;
+ picture.display_time=100;
+ videobuf_len=0;
+
+ telecine_cnt*=0.9; // drift out error
+ telecine_cnt+=frame_time-5.0/4.0;
+ mp_msg(MSGT_DECVIDEO,MSGL_DBG2,"\r telecine = %3.1f %5.3f \n",frame_time,telecine_cnt);
+
+ if(telecine){
+ frame_time=1;
+ if(telecine_cnt<-1.5 || telecine_cnt>1.5){
+ mp_tmsg(MSGT_DECVIDEO,MSGL_INFO,"\ndemux_mpg: 30000/1001fps NTSC content detected, switching framerate.\n");
+ telecine=0;
+ }
+ } else
+ if(telecine_cnt>-0.5 && telecine_cnt<0.5 && !force_fps){
+ sh_video->fps=sh_video->fps*4/5;
+ sh_video->frametime=sh_video->frametime*5/4;
+ mp_tmsg(MSGT_DECVIDEO,MSGL_INFO,"\ndemux_mpg: 24000/1001fps progressive NTSC content detected, switching framerate.\n");
+ telecine=1;
+ }
+ } else if(video_codec == VIDEO_MPEG4){
+ while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){
+ int i=sync_video_packet(d_video);
+ if(!i) return -1;
+ if(!read_video_packet(d_video)) return -1; // EOF
+ if(i==0x1B6) break;
+ }
+ *start=videobuffer; in_size=videobuf_len;
+ videobuf_len=0;
+ } else if(video_codec == VIDEO_H264){
+ int in_picture = 0;
+ while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE){
+ int i=sync_video_packet(d_video);
+ int pos = videobuf_len+4;
+ if(!i) return -1;
+ if(!read_video_packet(d_video)) return -1; // EOF
+ if((i&~0x60) == 0x107 && i != 0x107) {
+ h264_parse_sps(&picture, &(videobuffer[pos]), videobuf_len - pos);
+ if(picture.fps > 0) {
+ sh_video->fps=picture.fps;
+ sh_video->frametime=1.0/picture.fps;
+ }
+ i=sync_video_packet(d_video);
+ if(!i) return -1;
+ if(!read_video_packet(d_video)) return -1; // EOF
+ }
+
+ // here starts the access unit end detection code
+ // see the mail on MPlayer-dev-eng for details:
+ // Date: Sat, 17 Sep 2005 11:24:06 +0200
+ // Subject: Re: [MPlayer-dev-eng] [RFC] h264 ES parser problems
+ // Message-ID: <20050917092406.GA7699@rz.uni-karlsruhe.de>
+ if((i&~0x60) == 0x101 || (i&~0x60) == 0x102 || (i&~0x60) == 0x105)
+ // found VCL NAL with slice header i.e. start of current primary coded
+ // picture, so start scanning for the end now
+ in_picture = 1;
+ if (in_picture) {
+ i = sync_video_packet(d_video) & ~0x60; // code of next packet
+ if(i == 0x106 || i == 0x109) break; // SEI or access unit delim.
+ if(i == 0x101 || i == 0x102 || i == 0x105) {
+ // assuming arbitrary slice ordering is not allowed, the
+ // first_mb_in_slice (golomb encoded) value should be 0 then
+ // for the first VCL NAL in a picture
+ if (demux_peekc(d_video) & 0x80)
+ break;
+ }
+ }
+ }
+ *start=videobuffer; in_size=videobuf_len;
+ videobuf_len=0;
+ } else if(video_codec == VIDEO_VC1) {
+ while(videobuf_len<VIDEOBUFFER_SIZE-MAX_VIDEO_PACKET_SIZE) {
+ int i=sync_video_packet(d_video);
+ if(!i) return -1;
+ if(!read_video_packet(d_video)) return -1; // EOF
+ if(i==0x10D) break;
+ }
+ *start=videobuffer;
+ in_size=videobuf_len;
+ videobuf_len=0;
+ } else {
// frame-based file formats: (AVI,ASF,MOV)
in_size=ds_get_packet(d_video,start);
if(in_size<0) return -1; // EOF
+ }
//------------------------ frame decoded. --------------------
@@ -82,6 +571,7 @@ 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_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;
@@ -111,8 +601,21 @@ int video_read_frame(sh_video_t* sh_video,float* frame_time_ptr,unsigned char**
break;
}
-
- sh_video->pts=d_video->pts;
+ if(video_codec == VIDEO_MPEG12){
+ sh_video->pts+=frame_time;
+ if(picture_coding_type==1)
+ d_video->keyframe = true;
+ if(picture_coding_type<=2 && sh_video->i_pts){
+ sh_video->pts=sh_video->i_pts;
+ sh_video->i_pts=pts;
+ } else {
+ if(pts){
+ if(picture_coding_type<=2) sh_video->i_pts=pts;
+ else sh_video->pts=pts;
+ }
+ }
+ } else
+ sh_video->pts=d_video->pts;
if(frame_time_ptr) *frame_time_ptr=frame_time;
return in_size;