demux_asf.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 710 行 · 第 1/2 页
C
710 行
// ASF file parser for DEMUXER v0.3 by A'rpi/ESP-team#include <mplaylib.h>#include <mplaylib.h>#include <mplaylib.h>#include "config.h"#include "mp_msg.h"#include "help_mp.h"#include "stream/stream.h"#include "asf.h"#include "demuxer.h"#include "libvo/fastmemcpy.h"/* * Load 16/32-bit values in little endian byte order * from an unaligned address */#ifdef ARCH_X86#define LOAD_LE32(p) (*(unsigned int*)(p))#define LOAD_LE16(p) (*(unsigned short*)(p))#define LOAD_BE32(p) (((unsigned char*)(p))[3] | \ ((unsigned char*)(p))[2]<< 8 | \ ((unsigned char*)(p))[1]<<16 | \ ((unsigned char*)(p))[0]<<24 )#else#define LOAD_LE32(p) (((unsigned char*)(p))[0] | \ ((unsigned char*)(p))[1]<< 8 | \ ((unsigned char*)(p))[2]<<16 | \ ((unsigned char*)(p))[3]<<24 )#define LOAD_LE16(p) (((unsigned char*)(p))[0] | \ ((unsigned char*)(p))[1]<<8)#define LOAD_BE32(p) (*(unsigned int*)(p))#endif// defined at asfheader.c:extern int asf_check_header(demuxer_t *demuxer);extern int read_asf_header(demuxer_t *demuxer,struct asf_priv* asf);// based on asf file-format doc by Eugene [http://divx.euro.ru]static void asf_descrambling(unsigned char **src,unsigned len, struct asf_priv* asf){ unsigned char *dst=malloc(len); unsigned char *s2=*src; unsigned i=0,x,y; while(len>=asf->scrambling_h*asf->scrambling_w*asf->scrambling_b+i){// mp_msg(MSGT_DEMUX,MSGL_DBG4,"descrambling! (w=%d b=%d)\n",w,asf_scrambling_b); //i+=asf_scrambling_h*asf_scrambling_w; for(x=0;x<asf->scrambling_w;x++) for(y=0;y<asf->scrambling_h;y++){ fast_memcpy(dst+i,s2+(y*asf->scrambling_w+x)*asf->scrambling_b,asf->scrambling_b); i+=asf->scrambling_b; } s2+=asf->scrambling_h*asf->scrambling_w*asf->scrambling_b; } //if(i<len) fast_memcpy(dst+i,src+i,len-i); free(*src); *src = dst;}/***************************************************************** * \brief initializes asf private data * */static void init_priv (struct asf_priv* asf){ asf->last_vid_seq=-1; asf->vid_ext_timing_index=-1; asf->aud_ext_timing_index=-1; asf->vid_ext_frame_index=-1;}#ifdef USE_LIBAVCODEC_SO#include <ffmpeg/avcodec.h>#elif defined(USE_LIBAVCODEC)#include "libavcodec/avcodec.h"#else#define FF_INPUT_BUFFER_PADDING_SIZE 8#endifstatic void demux_asf_append_to_packet(demux_packet_t* dp,unsigned char *data,int len,int offs){ if(dp->len!=offs && offs!=-1) mp_msg(MSGT_DEMUX,MSGL_V,"warning! fragment.len=%d BUT next fragment offset=%d \n",dp->len,offs); dp->buffer=realloc(dp->buffer,dp->len+len+FF_INPUT_BUFFER_PADDING_SIZE); fast_memcpy(dp->buffer+dp->len,data,len); memset(dp->buffer+dp->len+len, 0, FF_INPUT_BUFFER_PADDING_SIZE); mp_dbg(MSGT_DEMUX,MSGL_DBG4,"data appended! %d+%d\n",dp->len,len); dp->len+=len;}static int demux_asf_read_packet(demuxer_t *demux,unsigned char *data,int len,int id,int seq,uint64_t time,unsigned short dur,int offs,int keyframe){ struct asf_priv* asf = demux->priv; demux_stream_t *ds=NULL; int close_seg=0; mp_dbg(MSGT_DEMUX,MSGL_DBG4,"demux_asf.read_packet: id=%d seq=%d len=%d\n",id,seq,len); if(demux->video->id==-1) if(demux->v_streams[id]) demux->video->id=id; if(demux->audio->id==-1) if(demux->a_streams[id]) demux->audio->id=id; if(id==demux->audio->id){ // audio ds=demux->audio; if(!ds->sh){ ds->sh=demux->a_streams[id]; mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected ASF audio ID = %d\n",ds->id); } } else if(id==demux->video->id){ // video ds=demux->video; if(!ds->sh){ ds->sh=demux->v_streams[id]; mp_msg(MSGT_DEMUX,MSGL_V,"Auto-selected ASF video ID = %d\n",ds->id); } } if(ds){ if(ds->asf_packet){ demux_packet_t* dp=ds->asf_packet; if (ds==demux->video && asf->asf_is_dvr_ms) { if (asf->new_vid_frame_seg) { dp->pos=demux->filepos; close_seg = 1; } else seq = ds->asf_seq; } else close_seg = ds->asf_seq!=seq; if(close_seg){ // closed segment, finalize packet: if(ds==demux->audio) if(asf->scrambling_h>1 && asf->scrambling_w>1 && asf->scrambling_b>0) asf_descrambling(&ds->asf_packet->buffer,ds->asf_packet->len,asf); ds_add_packet(ds,ds->asf_packet); ds->asf_packet=NULL; } else { // append data to it! demux_asf_append_to_packet(dp,data,len,offs); // we are ready now. return 1; } } // create new packet: { demux_packet_t* dp; if(offs>0){ mp_msg(MSGT_DEMUX,MSGL_V,"warning! broken fragment, %d bytes missing \n",offs); return 0; } dp=new_demux_packet(len); fast_memcpy(dp->buffer,data,len); if (asf->asf_is_dvr_ms) dp->pts=time*0.0000001; else dp->pts=time*0.001; dp->flags=keyframe;// if(ds==demux->video) printf("ASF time: %8d dur: %5d \n",time,dur); dp->pos=demux->filepos; ds->asf_packet=dp; ds->asf_seq=seq; // we are ready now. return 1; } } return 0;}/***************************************************************** * \brief read the replicated data associated with each segment * \parameter pp reference to replicated data * \parameter id stream number * \parameter seq media object number * \parameter keyframe key frame indicator - set to zero if keyframe, non-zero otherwise * \parameter seg_time set to payload time when valid, if audio or new video frame payload, zero otherwise * */static void get_payload_extension_data(demuxer_t *demux, unsigned char** pp, unsigned char id, unsigned int seq, int *keyframe, uint64_t *seg_time){ struct asf_priv* asf = demux->priv; uint64_t payload_time; //100ns units int i, ext_max, ext_timing_index; uint8_t *pi = *pp+4; if(demux->video->id==-1) if(demux->v_streams[id]) demux->video->id=id; if(demux->audio->id==-1) if(demux->a_streams[id]) demux->audio->id=id; if (id!=demux->video->id && id!=demux->audio->id) return; if (id==demux->video->id) { ext_max = asf->vid_repdata_count; ext_timing_index = asf->vid_ext_timing_index; } else { ext_max = asf->aud_repdata_count; ext_timing_index = asf->aud_ext_timing_index; } *seg_time=0.0; asf->new_vid_frame_seg = 0; for (i=0; i<ext_max; i++) { uint16_t payextsize; uint8_t segment_marker; if (id==demux->video->id) payextsize = asf->vid_repdata_sizes[i]; else payextsize = asf->aud_repdata_sizes[i]; if (payextsize == 65535) { payextsize = LOAD_LE16(pi); pi+=2; } // if this is the timing info extension then read the payload time if (i == ext_timing_index) payload_time = (uint64_t) LOAD_LE32(pi+8) | (uint64_t)LOAD_LE32(pi+8 + 4) << 32; // if this is the video frame info extension then // set the keyframe indicator, the 'new frame segment' indicator // and (initially) the 'frame time' if (i == asf->vid_ext_frame_index && id==demux->video->id) { segment_marker = pi[0]; // Known video stream segment_marker values that // contain useful information: // // NTSC/ATSC (29.97fps): 0X4A 01001010 // 0X4B 01001011 // 0X49 01001001 // // PAL/ATSC (25fps): 0X3A 00111010 // 0X3B 00111011 // 0X39 00111001 // // ATSC progressive (29.97fps): 0X7A 01111010 // 0X7B 01111011 // 0X79 01111001 // 11111111 // ^ this is new video frame marker // // ^^^^ these bits indicate the framerate // 0X4 is 29.97i, 0X3 is 25i, 0X7 is 29.97p, ???=25p // // ^^^ these bits indicate the frame type: // 001 means I-frame // 010 and 011 probably mean P and B asf->new_vid_frame_seg = (0X08 & segment_marker) && seq != asf->last_vid_seq; if (asf->new_vid_frame_seg) asf->last_vid_seq = seq; if (asf->avg_vid_frame_time == 0) { // set the average frame time initially (in 100ns units). // This is based on what works for known samples. // It can be extended if more samples of different types can be obtained. if (((segment_marker & 0XF0) >> 4) == 4) { asf->avg_vid_frame_time = (uint64_t)((1.001 / 30.0) * 10000000.0); asf->know_frame_time=1; } else if (((segment_marker & 0XF0) >> 4) == 3) { asf->avg_vid_frame_time = (uint64_t)(0.04 * 10000000.0); asf->know_frame_time=1; } else if (((segment_marker & 0XF0) >> 4) == 6) { asf->avg_vid_frame_time = (uint64_t)(0.02 * 10000000.0); asf->know_frame_time=1; } else if (((segment_marker & 0XF0) >> 4) == 7) { asf->avg_vid_frame_time = (uint64_t)((1.001 / 60.0) * 10000000.0); asf->know_frame_time=1; } else { // we dont know the frame time initially so // make a guess and then recalculate as we go. asf->avg_vid_frame_time = (uint64_t)((1.001 / 60.0) * 10000000.0); asf->know_frame_time=0; } } *keyframe = (asf->new_vid_frame_seg && (segment_marker & 0X07) == 1); } pi +=payextsize; } if (id==demux->video->id && asf->new_vid_frame_seg) { asf->vid_frame_ct++; // Some samples only have timings on key frames and // the rest contain non-cronological timestamps. Interpolating // the values between key frames works for all samples. if (*keyframe) { asf->found_first_key_frame=1; if (!asf->know_frame_time && asf->last_key_payload_time > 0) { // We dont know average frametime so recalculate. // Giving precedence to the 'weight' of the existing // average limits damage done to new value when there is // a sudden time jump which happens occasionally. asf->avg_vid_frame_time = (0.9 * asf->avg_vid_frame_time) + (0.1 * ((payload_time - asf->last_key_payload_time) / asf->vid_frame_ct)); } asf->last_key_payload_time = payload_time; asf->vid_frame_ct = 1; *seg_time = payload_time; } else *seg_time = (asf->last_key_payload_time + (asf->avg_vid_frame_time * (asf->vid_frame_ct-1))); } if (id==demux->audio->id) { if (payload_time != -1) asf->last_aud_diff = payload_time - asf->last_aud_pts; asf->last_aud_pts += asf->last_aud_diff; *seg_time = asf->last_aud_pts; }}//static int num_elementary_packets100=0;//static int num_elementary_packets101=0;// return value:// 0 = EOF or no stream found// 1 = successfully read a packetstatic int demux_asf_fill_buffer(demuxer_t *demux, demux_stream_t *ds){ struct asf_priv* asf = demux->priv; demux->filepos=stream_tell(demux->stream); // Brodcast stream have movi_start==movi_end // Better test ? if((demux->movi_start < demux->movi_end) && (demux->filepos>=demux->movi_end)){ demux->stream->eof=1; return 0; } stream_read(demux->stream,asf->packet,asf->packetsize); if(demux->stream->eof) return 0; // EOF { unsigned char* p=asf->packet; unsigned char* p_end=asf->packet+asf->packetsize; unsigned char flags=p[0]; unsigned char segtype=p[1]; unsigned padding; unsigned plen; unsigned sequence; unsigned long time=0; unsigned short duration=0; int segs=1; unsigned char segsizetype=0x80; int seg=-1;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?