📄 videodec.c
字号:
/*mediastreamer2 library - modular sound and video processing and streamingCopyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org)This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#ifdef HAVE_CONFIG_H#include "mediastreamer-config.h"#endif#include "ffmpeg-priv.h"#include "mediastreamer2/msfilter.h"#include "mediastreamer2/msvideo.h"#include "rfc2429.h"extern void ms_ffmpeg_check_init();typedef struct DecState{ AVCodecContext av_context; AVCodec *av_codec; enum CodecID codec; mblk_t *input; YuvBuf outbuf; mblk_t *yuv_msg; struct SwsContext *sws_ctx; int output_pix_fmt; uint8_t dci[512]; int dci_size; bool_t snow_initialized;}DecState;static void dec_init(MSFilter *f, enum CodecID cid){ DecState *s=(DecState *)ms_new0(DecState,1); ms_ffmpeg_check_init(); avcodec_get_context_defaults(&s->av_context); s->av_codec=NULL; s->codec=cid; s->input=NULL; s->yuv_msg=NULL; s->output_pix_fmt=PIX_FMT_YUV420P; s->snow_initialized=FALSE; s->outbuf.w=0; s->outbuf.h=0; s->sws_ctx=NULL; f->data=s; s->av_codec=avcodec_find_decoder(s->codec); if (s->av_codec==NULL){ ms_error("Could not find decoder %i!",s->codec); } /* s->av_context.width=MS_VIDEO_SIZE_QCIF_W; s->av_context.height=MS_VIDEO_SIZE_QCIF_H; */}static void dec_h263_init(MSFilter *f){ dec_init(f,CODEC_ID_H263);}static void dec_mpeg4_init(MSFilter *f){ dec_init(f,CODEC_ID_MPEG4);}static void dec_mjpeg_init(MSFilter *f){ dec_init(f,CODEC_ID_MJPEG);}static void dec_snow_init(MSFilter *f){ dec_init(f,CODEC_ID_SNOW);}static void dec_uninit(MSFilter *f){ DecState *s=(DecState*)f->data; if (s->input!=NULL) freemsg(s->input); if (s->yuv_msg!=NULL) freemsg(s->yuv_msg); if (s->sws_ctx!=NULL){ sws_freeContext(s->sws_ctx); s->sws_ctx=NULL; } ms_free(s);}static int dec_add_fmtp(MSFilter *f, void *data){ const char *fmtp=(const char*)data; DecState *s=(DecState*)f->data; char config[512]; if (fmtp_get_value(fmtp,"config",config,sizeof(config))){ /*convert hexa decimal config string into a bitstream */ int i,j,max=strlen(config); char octet[3]; octet[2]=0; for(i=0,j=0;i<max;i+=2,++j){ octet[0]=config[i]; octet[1]=config[i+1]; s->dci[j]=strtol(octet,NULL,16); } s->dci_size=j; ms_message("Got mpeg4 config string: %s",config); } return 0;}static void dec_preprocess(MSFilter *f){ DecState *s=(DecState*)f->data; int error; /* we must know picture size before initializing snow decoder*/ if (s->codec!=CODEC_ID_SNOW){ error=avcodec_open(&s->av_context, s->av_codec); if (error!=0) ms_error("avcodec_open() failed: %i",error); if (s->codec==CODEC_ID_MPEG4 && s->dci_size>0){ s->av_context.extradata=s->dci; s->av_context.extradata_size=s->dci_size; } }}static void dec_postprocess(MSFilter *f){ DecState *s=(DecState*)f->data; if (s->av_context.codec!=NULL){ avcodec_close(&s->av_context); s->av_context.codec=NULL; }}static mblk_t * skip_rfc2190_header(mblk_t *inm){ if (msgdsize(inm) >= 4) { uint8_t *ph = inm->b_rptr; int F = (ph[0]>>7) & 0x1; int P = (ph[0]>>6) & 0x1; if (F == 0) inm->b_rptr += 4; // mode A else if (P == 0) inm->b_rptr += 8; // mode B else inm->b_rptr += 12; // mode C } else { freemsg(inm); inm=NULL; } return inm;}static mblk_t * skip_rfc2429_header(mblk_t *inm){ if (msgdsize(inm) >= 2){ uint32_t *p = (uint32_t*)inm->b_rptr; uint8_t *ph=inm->b_rptr; int PLEN; int gob_num; bool_t P; P=rfc2429_get_P(ph); PLEN=rfc2429_get_PLEN(ph); /*printf("receiving new packet; P=%i; V=%i; PLEN=%i; PEBIT=%i\n",P,rfc2429_get_V(ph),PLEN,rfc2429_get_PEBIT(ph)); */ gob_num = (ntohl(*p) >> 10) & 0x1f; /*ms_message("gob %i, size %i", gob_num, msgdsize(inm)); ms_message("ms_AVdecoder_process: received %08x %08x", ntohl(p[0]), ntohl(p[1]));*/ /* remove H.263 Payload Header */ if (PLEN>0){ /* we ignore the redundant picture header and directly go to the bitstream */ inm->b_rptr+=PLEN; } if (P){ inm->b_rptr[0]=inm->b_rptr[1]=0; }else{ /* no PSC omitted */ inm->b_rptr+=2; } return inm; }else freemsg(inm); return NULL;}static mblk_t * parse_snow_header(DecState *s,mblk_t *inm){ if (msgdsize(inm) >= 4){ uint32_t h = ntohl(*(uint32_t*)inm->b_rptr); if (!s->snow_initialized){ int error; s->av_context.width=h>>16; s->av_context.height=h&0xffff; error=avcodec_open(&s->av_context, s->av_codec); if (error!=0) ms_error("avcodec_open() failed for snow: %i",error); else { s->snow_initialized=TRUE; ms_message("Snow decoder initialized,size=%ix%i", s->av_context.width, s->av_context.height); } } inm->b_rptr+=4; return inm; }else { freemsg(inm); return NULL; }}static mblk_t *get_as_yuvmsg(MSFilter *f, DecState *s, AVFrame *orig){ AVCodecContext *ctx=&s->av_context; if (s->outbuf.w!=ctx->width || s->outbuf.h!=ctx->height){ if (s->sws_ctx!=NULL){ sws_freeContext(s->sws_ctx); s->sws_ctx=NULL; } s->yuv_msg=yuv_buf_alloc(&s->outbuf,ctx->width,ctx->height); s->outbuf.w=ctx->width; s->outbuf.h=ctx->height; s->sws_ctx=sws_getContext(ctx->width,ctx->height,ctx->pix_fmt, ctx->width,ctx->height,s->output_pix_fmt,SWS_FAST_BILINEAR, NULL, NULL, NULL); } if (sws_scale(s->sws_ctx,orig->data,orig->linesize, 0, ctx->height, s->outbuf.planes, s->outbuf.strides)<0){ ms_error("%s: error in sws_scale().",f->desc->name); } return dupmsg(s->yuv_msg);}static void dec_process_frame(MSFilter *f, mblk_t *inm){ DecState *s=(DecState*)f->data; AVFrame orig; int got_picture; /* get a picture from the input queue */ if (f->desc->id==MS_H263_DEC_ID) inm=skip_rfc2429_header(inm); else if (f->desc->id==MS_H263_OLD_DEC_ID) inm=skip_rfc2190_header(inm); else if (s->codec==CODEC_ID_SNOW && s->input==NULL) inm=parse_snow_header(s,inm); if (inm){ /* accumulate the video packet until we have the rtp markbit*/ if (s->input==NULL){ s->input=inm; }else{ concatb(s->input,inm); } if (mblk_get_marker_info(inm)){ mblk_t *frame; int remain,len; /*ms_message("got marker bit !");*/ /*append some padding bytes for ffmpeg to safely read extra bytes...*/ msgpullup(s->input,msgdsize(s->input)+8); frame=s->input; s->input=NULL; while ( (remain=frame->b_wptr-frame->b_rptr)> 0) { len=avcodec_decode_video(&s->av_context,&orig,&got_picture,(uint8_t*)frame->b_rptr,remain ); if (len<=0) { ms_warning("ms_AVdecoder_process: error %i.",len); break; } if (got_picture) { ms_queue_put(f->outputs[0],get_as_yuvmsg(f,s,&orig)); } frame->b_rptr+=len; } freemsg(frame); } }}static void dec_process(MSFilter *f){ mblk_t *inm; while((inm=ms_queue_get(f->inputs[0]))!=0){ dec_process_frame(f,inm); }}static MSFilterMethod methods[]={ { MS_FILTER_ADD_FMTP , dec_add_fmtp }, { 0 , NULL }};#ifdef _MSC_VERMSFilterDesc ms_h263_dec_desc={ MS_H263_DEC_ID, "MSH263Dec", "A H.263 decoder using ffmpeg library", MS_FILTER_DECODER, "H263-1998", 1, 1, dec_h263_init, dec_preprocess, dec_process, dec_postprocess, dec_uninit, methods};MSFilterDesc ms_h263_old_dec_desc={ MS_H263_DEC_ID, "MSH263OldDec", "A H.263 decoder using ffmpeg library", MS_FILTER_DECODER, "H263", 1, 1, dec_h263_init, dec_preprocess, dec_process, dec_postprocess, dec_uninit, methods};MSFilterDesc ms_mpeg4_dec_desc={ MS_MPEG4_DEC_ID, "MSMpeg4Dec", "A MPEG4 decoder using ffmpeg library", MS_FILTER_DECODER, "MP4V-ES", 1, 1, dec_mpeg4_init, dec_preprocess, dec_process, dec_postprocess, dec_uninit, methods};MSFilterDesc ms_mjpeg_dec_desc={ MS_MJPEG_DEC_ID, "MSMJpegDec", "A MJPEG decoder using ffmpeg library", MS_FILTER_DECODER, "MJPEG", 1, 1, dec_mjpeg_init, dec_preprocess, dec_process, dec_postprocess, dec_uninit, methods};MSFilterDesc ms_snow_dec_desc={ MS_SNOW_DEC_ID, "MSSnowDec", "A snow decoder using ffmpeg library", MS_FILTER_DECODER, "snow", 1, 1, dec_snow_init, dec_preprocess, dec_process, dec_postprocess, dec_uninit, methods};#elseMSFilterDesc ms_h263_dec_desc={ .id=MS_H263_DEC_ID, .name="MSH263Dec", .text="A H.263 decoder using ffmpeg library", .category=MS_FILTER_DECODER, .enc_fmt="H263-1998", .ninputs=1, .noutputs=1, .init=dec_h263_init, .preprocess=dec_preprocess, .process=dec_process, .postprocess=dec_postprocess, .uninit=dec_uninit, .methods= methods};MSFilterDesc ms_h263_old_dec_desc={ .id=MS_H263_OLD_DEC_ID, .name="MSH263OldDec", .text="A H.263 decoder using ffmpeg library", .category=MS_FILTER_DECODER, .enc_fmt="H263", .ninputs=1, .noutputs=1, .init=dec_h263_init, .preprocess=dec_preprocess, .process=dec_process, .postprocess=dec_postprocess, .uninit=dec_uninit, .methods= methods};MSFilterDesc ms_mpeg4_dec_desc={ .id=MS_MPEG4_DEC_ID, .name="MSMpeg4Dec", .text="A MPEG4 decoder using ffmpeg library", .category=MS_FILTER_DECODER, .enc_fmt="MP4V-ES", .ninputs=1, .noutputs=1, .init=dec_mpeg4_init, .preprocess=dec_preprocess, .process=dec_process, .postprocess=dec_postprocess, .uninit=dec_uninit, .methods= methods};MSFilterDesc ms_mjpeg_dec_desc={ .id=MS_MJPEG_DEC_ID, .name="MSMJpegDec", .text="A MJEPG decoder using ffmpeg library", .category=MS_FILTER_DECODER, .enc_fmt="MJPEG", .ninputs=1, .noutputs=1, .init=dec_mjpeg_init, .preprocess=dec_preprocess, .process=dec_process, .postprocess=dec_postprocess, .uninit=dec_uninit, .methods= methods};MSFilterDesc ms_snow_dec_desc={ .id=MS_SNOW_DEC_ID, .name="MSSnowDec", .text="A snow decoder using ffmpeg library", .category=MS_FILTER_DECODER, .enc_fmt="x-snow", .ninputs=1, .noutputs=1, .init=dec_snow_init, .preprocess=dec_preprocess, .process=dec_process, .postprocess=dec_postprocess, .uninit=dec_uninit, .methods= methods};#endifMS_FILTER_DESC_EXPORT(ms_mpeg4_dec_desc)MS_FILTER_DESC_EXPORT(ms_h263_dec_desc)MS_FILTER_DESC_EXPORT(ms_h263_old_dec_desc)MS_FILTER_DESC_EXPORT(ms_mjpeg_dec_desc)MS_FILTER_DESC_EXPORT(ms_snow_dec_desc)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -