📄 ffmpeg_decode.c
字号:
default: capability->cap.valueInt = 0; break; } return GF_OK;}static GF_Err FFDEC_SetCapabilities(GF_BaseDecoder *plug, GF_CodecCapability capability){ FFDec *ffd = (FFDec *)plug->privateStack; switch (capability.CapCode) { case GF_CODEC_WAIT_RAP: ffd->frame_start = 0; if (ffd->st==GF_STREAM_VISUAL) avcodec_flush_buffers(ffd->ctx); return GF_OK; default: /*return unsupported to avoid confusion by the player (like color space changing ...) */ return GF_NOT_SUPPORTED; }}static GF_Err FFDEC_ProcessData(GF_MediaDecoder *plug, char *inBuffer, u32 inBufferLength, u16 ES_ID, char *outBuffer, u32 *outBufferLength, u8 PaddingBits, u32 mmlevel){ s32 gotpic; u32 outsize; FFDec *ffd = plug->privateStack; /*WARNING: this breaks H264 (and maybe others) decoding, disabled for now*/#if 1 if (!ffd->ctx->hurry_up) { switch (mmlevel) { case GF_CODEC_LEVEL_SEEK: case GF_CODEC_LEVEL_DROP: /*skip as much as possible*/ ffd->ctx->hurry_up = 5; break; case GF_CODEC_LEVEL_VERY_LATE: case GF_CODEC_LEVEL_LATE: /*skip B-frames*/ ffd->ctx->hurry_up = 1; break; default: ffd->ctx->hurry_up = 0; break; } }#endif /*audio stream*/ if (ffd->st==GF_STREAM_AUDIO) { s32 len; u32 buf_size = (*outBufferLength); (*outBufferLength) = 0; /*seeking don't decode*/ if (!inBuffer || (mmlevel == GF_CODEC_LEVEL_SEEK)) { *outBufferLength = 0; ffd->frame_start = 0; return GF_OK; } if (ffd->frame_start>inBufferLength) ffd->frame_start = 0;redecode: len = avcodec_decode_audio(ffd->ctx, (short *)ffd->audio_buf, &gotpic, inBuffer + ffd->frame_start, inBufferLength - ffd->frame_start); if (len<0) { ffd->frame_start = 0; return GF_NON_COMPLIANT_BITSTREAM; } if (gotpic<0) { ffd->frame_start = 0; return GF_OK; } ffd->ctx->hurry_up = 0; if (ffd->ctx->frame_size < gotpic) ffd->ctx->frame_size = gotpic; /*first config*/ if (!ffd->out_size) { ffd->ctx->bits_per_sample = 16; ffd->out_size = ffd->ctx->bits_per_sample * ffd->ctx->channels * ffd->ctx->frame_size / 8; } if (ffd->out_size < (u32) gotpic) { ffd->ctx->bits_per_sample = 16; /*looks like relying on frame_size is not a good idea for all codecs, so we use gotpic*/ (*outBufferLength) = ffd->out_size = gotpic; return GF_BUFFER_TOO_SMALL; } if (ffd->out_size > buf_size) { /*don't use too small output chunks otherwise we'll never have enough when mixing - we could also request more slots in the composition memory but let's not waste mem*/ if (ffd->out_size < (u32) 576*ffd->ctx->channels) ffd->out_size=ffd->ctx->channels*576; (*outBufferLength) = ffd->out_size; return GF_BUFFER_TOO_SMALL; } /*we're sure to have at least gotpic bytes available in output*/ memcpy(outBuffer, ffd->audio_buf, sizeof(char) * gotpic); (*outBufferLength) += gotpic; outBuffer += gotpic; ffd->frame_start += len; if (inBufferLength <= ffd->frame_start) { ffd->frame_start = 0; return GF_OK; } /*still space go on*/ if ((*outBufferLength)+ffd->ctx->frame_size<ffd->out_size) goto redecode; /*more frames in the current sample*/ return GF_PACKED_FRAMES; } else { s32 w = ffd->ctx->width; s32 h = ffd->ctx->height; if (ffd->check_h264_isma) { /*for AVC bitstreams after ISMA decryption, in case (as we do) the decryption DRM tool doesn't put back nalu size, do it ourselves...*/ if (inBuffer && !inBuffer[0] && !inBuffer[1] && !inBuffer[2] && (inBuffer[3]==0x01)) { u32 nalu_size; u32 remain = inBufferLength; char *start, *end; start = inBuffer; end = inBuffer + 4; while (remain>4) { if (!end[0] && !end[1] && !end[2] && (end[3]==0x01)) { nalu_size = end - start - 4; start[0] = (nalu_size>>24)&0xFF; start[1] = (nalu_size>>16)&0xFF; start[2] = (nalu_size>>8)&0xFF; start[3] = (nalu_size)&0xFF; start = end; end = start+4; continue; } end++; remain--; } nalu_size = end - start - 4; start[0] = (nalu_size>>24)&0xFF; start[1] = (nalu_size>>16)&0xFF; start[2] = (nalu_size>>8)&0xFF; start[3] = (nalu_size)&0xFF; ffd->check_h264_isma = 2; } /*if we had ISMA E&A and lost it this is likely due to a pck loss - do NOT switch back to regular*/ else if (ffd->check_h264_isma == 1) { ffd->check_h264_isma = 0; } } if (avcodec_decode_video(ffd->ctx, ffd->frame, &gotpic, inBuffer, inBufferLength) < 0) { if (!ffd->check_short_header) { return GF_NON_COMPLIANT_BITSTREAM; } /*switch to H263 (ffmpeg MPEG-4 codec doesn't understand short headers)*/ { u32 old_codec = ffd->codec->id; ffd->check_short_header = 0; /*OK we loose the DSI stored in the codec context, but H263 doesn't need any, and if we're here this means the DSI was broken, so no big deal*/ avcodec_close(ffd->ctx); ffd->codec = avcodec_find_decoder(CODEC_ID_H263); if (!ffd->codec || (avcodec_open(ffd->ctx, ffd->codec)<0)) return GF_NON_COMPLIANT_BITSTREAM; if (avcodec_decode_video(ffd->ctx, ffd->frame, &gotpic, inBuffer, inBufferLength) < 0) { /*nope, stay in MPEG-4*/ avcodec_close(ffd->ctx); ffd->codec = avcodec_find_decoder(old_codec); assert(ffd->codec); avcodec_open(ffd->ctx, ffd->codec); return GF_NON_COMPLIANT_BITSTREAM; } } } ffd->ctx->hurry_up = 0; /*recompute outsize in case on-the-fly change*/ if ((w != ffd->ctx->width) || (h != ffd->ctx->height)) { outsize = ffd->ctx->width * ffd->ctx->height * 3; if (ffd->pix_fmt!=GF_PIXEL_RGB_24) outsize /= 2; ffd->out_size = outsize; *outBufferLength = ffd->out_size; if (ffd->check_h264_isma) { inBuffer[0] = inBuffer[1] = inBuffer[2] = 0; inBuffer[3] = 1; } return GF_BUFFER_TOO_SMALL; } /*check PAR in case on-the-fly change*/ if (!ffd->no_par_update && ffd->ctx->sample_aspect_ratio.num && ffd->ctx->sample_aspect_ratio.den) { outsize = (ffd->ctx->sample_aspect_ratio.num<<16) | ffd->ctx->sample_aspect_ratio.den; if (outsize!=ffd->previous_par) { ffd->previous_par=outsize; *outBufferLength = ffd->out_size; return GF_BUFFER_TOO_SMALL; } } *outBufferLength = 0; if (mmlevel == GF_CODEC_LEVEL_SEEK) return GF_OK; if (gotpic) {//#if defined(_WIN32_WCE) || defined(__SYMBIAN32__)#if 1 if (ffd->pix_fmt==GF_PIXEL_RGB_24) { memcpy(outBuffer, ffd->frame->data[0], sizeof(char)*3*ffd->ctx->width); } else { s32 i; char *pYO, *pUO, *pVO; unsigned char *pYD, *pUD, *pVD; pYO = ffd->frame->data[0]; pUO = ffd->frame->data[1]; pVO = ffd->frame->data[2]; pYD = outBuffer; pUD = outBuffer + ffd->ctx->width * ffd->ctx->height; pVD = outBuffer + 5 * ffd->ctx->width * ffd->ctx->height / 4; for (i=0; i<ffd->ctx->height; i++) { memcpy(pYD, pYO, sizeof(char) * ffd->ctx->width); pYD += ffd->ctx->width; pYO += ffd->frame->linesize[0]; if (i%2) continue; memcpy(pUD, pUO, sizeof(char) * ffd->ctx->width/2); memcpy(pVD, pVO, sizeof(char) * ffd->ctx->width/2); pUD += ffd->ctx->width/2; pVD += ffd->ctx->width/2; pUO += ffd->frame->linesize[1]; pVO += ffd->frame->linesize[2]; } *outBufferLength = ffd->out_size; }#else AVPicture pict; u32 pix_out; memset(&pict, 0, sizeof(pict)); if (ffd->pix_fmt==GF_PIXEL_RGB_24) { pict.data[0] = outBuffer; pict.linesize[0] = 3*ffd->ctx->width; pix_out = PIX_FMT_RGB24; } else { pict.data[0] = outBuffer; pict.data[1] = outBuffer + ffd->ctx->width * ffd->ctx->height; pict.data[2] = outBuffer + 5 * ffd->ctx->width * ffd->ctx->height / 4; pict.linesize[0] = ffd->ctx->width; pict.linesize[1] = pict.linesize[2] = ffd->ctx->width/2; pix_out = PIX_FMT_YUV420P; if (!mmlevel && ffd->frame->interlaced_frame) { avpicture_deinterlace((AVPicture *) ffd->frame, (AVPicture *) ffd->frame, ffd->ctx->pix_fmt, ffd->ctx->width, ffd->ctx->height); } } pict.data[3] = 0; pict.linesize[3] = 0; img_convert(&pict, pix_out, (AVPicture *) ffd->frame, ffd->ctx->pix_fmt, ffd->ctx->width, ffd->ctx->height); *outBufferLength = ffd->out_size;#endif } } return GF_OK;}static Bool FFDEC_CanHandleStream(GF_BaseDecoder *plug, u32 StreamType, u32 ObjectType, char *decSpecInfo, u32 decSpecInfoSize, u32 PL){ GF_BitStream *bs; u32 codec_id; Bool check_4cc; FFDec *ffd = plug->privateStack; if (!ObjectType) { if ((StreamType==GF_STREAM_VISUAL) || (StreamType==GF_STREAM_AUDIO)) return 1; return 0; } /*store types*/ ffd->oti = ObjectType; ffd->st = StreamType; codec_id = 0; check_4cc = 0; /*private from FFMPEG input*/ if (ObjectType == GPAC_FFMPEG_CODECS_OTI) { bs = gf_bs_new(decSpecInfo, decSpecInfoSize, GF_BITSTREAM_READ); codec_id = gf_bs_read_u32(bs); gf_bs_del(bs); } /*private from IsoMedia input*/ else if (ObjectType == GPAC_EXTRA_CODECS_OTI) { bs = gf_bs_new(decSpecInfo, decSpecInfoSize, GF_BITSTREAM_READ); codec_id = gf_bs_read_u32(bs); check_4cc = 1; gf_bs_del(bs); } /*std MPEG-4 audio*/ else if (StreamType==GF_STREAM_AUDIO) { if ((ObjectType==0x69) || (ObjectType==0x6B)) codec_id = CODEC_ID_MP2; } /*std MPEG-4 visual*/ else if (StreamType==GF_STREAM_VISUAL) { switch (ObjectType) { /*MPEG-4 v1 simple profile*/ case 0x20: codec_id = CODEC_ID_MPEG4; break; /*H264 (not std OTI, just the way we use it internally)*/ case 0x21: codec_id = CODEC_ID_H264; break; /*MPEG1 video*/ case 0x6A: /*MPEG2 video*/ case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: codec_id = CODEC_ID_MPEG2VIDEO; break; /*JPEG*/ case 0x6C: return 0; /*I'm having troubles with ffmpeg & jpeg, it appears to crash randomly*/ return 1; default: return 0; } } /*NeroDigital DVD subtitles*/ else if ((StreamType==GF_STREAM_ND_SUBPIC) && (ObjectType==0xe0)) return 1; if (!codec_id) return 0; if (check_4cc && (ffmpeg_get_codec(codec_id) != NULL)) return 1; if (avcodec_find_decoder(codec_id) != NULL) return 1; return 0;}static char szCodec[100];static const char *FFDEC_GetCodecName(GF_BaseDecoder *dec){ FFDec *ffd = dec->privateStack; if (ffd->codec) { sprintf(szCodec, "FFMPEG %s", ffd->codec->name ? ffd->codec->name : "unknown"); return szCodec; } return NULL;}void *FFDEC_Load(){ GF_MediaDecoder *ptr; FFDec *priv; avcodec_init(); avcodec_register_all(); GF_SAFEALLOC(ptr , GF_MediaDecoder); GF_SAFEALLOC(priv , FFDec); ptr->privateStack = priv; ptr->AttachStream = FFDEC_AttachStream; ptr->DetachStream = FFDEC_DetachStream; ptr->GetCapabilities = FFDEC_GetCapabilities; ptr->SetCapabilities = FFDEC_SetCapabilities; ptr->CanHandleStream = FFDEC_CanHandleStream; ptr->GetName = FFDEC_GetCodecName; ptr->ProcessData = FFDEC_ProcessData; GF_REGISTER_MODULE_INTERFACE(ptr, GF_MEDIA_DECODER_INTERFACE, "FFMPEG decoder", "gpac distribution"); return (GF_BaseInterface *) ptr;}void FFDEC_Delete(void *ifce){ GF_BaseDecoder *dec = ifce; FFDec *ffd = dec->privateStack; if (ffd->ctx) avcodec_close(ffd->ctx); free(ffd); free(dec);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -