📄 ffmpeg_decode.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / FFMPEG module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "ffmpeg_in.h"#include <gpac/avparse.h>static void gf_av_vlog(void* avcl, int level, const char *fmt, va_list vl){ char szMsg[1024]; vsprintf(szMsg, fmt, vl); GF_LOG(GF_LOG_DEBUG, GF_LOG_CODEC, (szMsg));}static AVCodec *ffmpeg_get_codec(u32 codec_4cc){ char name[5]; AVCodec *codec; strcpy(name, gf_4cc_to_str(codec_4cc)); codec = avcodec_find_decoder_by_name(name); if (!codec) { strupr(name); codec = avcodec_find_decoder_by_name(name); if (!codec) { strlwr(name); codec = avcodec_find_decoder_by_name(name); } } /*custom mapings*/ if (!codec) { if (!stricmp(name, "s263")) codec = avcodec_find_decoder_by_name("h263"); else if (!stricmp(name, "samr") || !stricmp(name, "amr ")) codec = avcodec_find_decoder_by_name("amr_nb"); else if (!stricmp(name, "sawb")) codec = avcodec_find_decoder_by_name("amr_wb"); } return codec;}static void FFDEC_LoadDSI(FFDec *ffd, GF_BitStream *bs, Bool from_ff_demux){ u32 dsi_size; if (!ffd->codec) return; dsi_size = (u32) gf_bs_available(bs); if (!dsi_size) return; /*demuxer is ffmpeg, extra data can be copied directly*/ if (from_ff_demux) { free(ffd->ctx->extradata); ffd->ctx->extradata_size = dsi_size; ffd->ctx->extradata = (uint8_t*) malloc(sizeof(char)*ffd->ctx->extradata_size); gf_bs_read_data(bs, ffd->ctx->extradata, ffd->ctx->extradata_size); return; } switch (ffd->codec->id) { case CODEC_ID_SVQ3: { u32 at_type, size; size = gf_bs_read_u32(bs); /*there should be an 'SMI' entry*/ at_type = gf_bs_read_u32(bs); if (at_type == GF_4CC('S', 'M', 'I', ' ')) { free(ffd->ctx->extradata); ffd->ctx->extradata_size = 0x5a + size; ffd->ctx->extradata = (uint8_t*) malloc(sizeof(char)*ffd->ctx->extradata_size); strcpy(ffd->ctx->extradata, "SVQ3"); gf_bs_read_data(bs, (unsigned char *)ffd->ctx->extradata + 0x5a, size); } } break; default: free(ffd->ctx->extradata); ffd->ctx->extradata_size = dsi_size; ffd->ctx->extradata = (uint8_t*) malloc(sizeof(char)*ffd->ctx->extradata_size); gf_bs_read_data(bs, ffd->ctx->extradata, ffd->ctx->extradata_size); break; }}static GF_Err FFDEC_AttachStream(GF_BaseDecoder *plug, u16 ES_ID, char *decSpecInfo, u32 decSpecInfoSize, u16 DependsOnES_ID, u32 objectTypeIndication, Bool UpStream){ u32 codec_id; int gotpic; GF_BitStream *bs; GF_M4VDecSpecInfo dsi; GF_Err e; FFDec *ffd = (FFDec *)plug->privateStack; if (ffd->ES_ID || DependsOnES_ID || UpStream) return GF_NOT_SUPPORTED; if (!ffd->oti) return GF_NOT_SUPPORTED; ffd->ES_ID = ES_ID; ffd->ctx = avcodec_alloc_context(); /*private FFMPEG DSI*/ if (ffd->oti == GPAC_FFMPEG_CODECS_OTI) { bs = gf_bs_new(decSpecInfo, decSpecInfoSize, GF_BITSTREAM_READ); codec_id = gf_bs_read_u32(bs); if (ffd->st==GF_STREAM_AUDIO) { ffd->ctx->codec_type = CODEC_TYPE_AUDIO; ffd->ctx->sample_rate = gf_bs_read_u32(bs); ffd->ctx->channels = gf_bs_read_u16(bs); ffd->ctx->bits_per_sample = gf_bs_read_u16(bs); /*force 16 bits output*/ ffd->ctx->bits_per_sample = 16; ffd->ctx->frame_size = gf_bs_read_u16(bs); ffd->ctx->block_align = gf_bs_read_u16(bs); } else if (ffd->st==GF_STREAM_VISUAL) { ffd->ctx->codec_type = CODEC_TYPE_VIDEO; ffd->ctx->width = gf_bs_read_u32(bs); ffd->ctx->height = gf_bs_read_u32(bs); } ffd->ctx->codec_tag = gf_bs_read_u32(bs); ffd->ctx->bit_rate = gf_bs_read_u32(bs); ffd->codec = avcodec_find_decoder(codec_id); FFDEC_LoadDSI(ffd, bs, 1); gf_bs_del(bs); } /*private QT DSI*/ else if (ffd->oti == GPAC_EXTRA_CODECS_OTI) { bs = gf_bs_new(decSpecInfo, decSpecInfoSize, GF_BITSTREAM_READ); codec_id = gf_bs_read_u32(bs); if (ffd->st==GF_STREAM_AUDIO) { ffd->ctx->codec_type = CODEC_TYPE_AUDIO; ffd->ctx->sample_rate = gf_bs_read_u16(bs); ffd->ctx->frame_size = gf_bs_read_u16(bs); ffd->ctx->channels = gf_bs_read_u8(bs); ffd->ctx->bits_per_sample = gf_bs_read_u8(bs); /*packed mode*/ gf_bs_read_u8(bs); /*just in case...*/ if (codec_id == GF_4CC('a', 'm', 'r', ' ')) { ffd->ctx->sample_rate = 8000; ffd->ctx->channels = 1; ffd->ctx->bits_per_sample = 16; ffd->ctx->frame_size = 160; } } else if (ffd->st==GF_STREAM_VISUAL) { ffd->ctx->codec_type = CODEC_TYPE_VIDEO; ffd->ctx->width = gf_bs_read_u16(bs); ffd->ctx->height = gf_bs_read_u16(bs); } ffd->codec = ffmpeg_get_codec(codec_id); FFDEC_LoadDSI(ffd, bs, 0); gf_bs_del(bs); } /*use std MPEG-4 st/oti*/ else { u32 codec_id = 0; if (ffd->st==GF_STREAM_VISUAL) { ffd->ctx->codec_type = CODEC_TYPE_VIDEO; switch (ffd->oti) { case 0x20: codec_id = CODEC_ID_MPEG4; break; case 0x21: codec_id = CODEC_ID_H264; /*ffmpeg H264/AVC needs that*/ ffd->ctx->codec_tag = 0x31637661; break; case 0x6A: case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: codec_id = CODEC_ID_MPEG2VIDEO; break; case 0x6C: codec_id = CODEC_ID_MJPEG; break; case 0xFF: codec_id = CODEC_ID_SVQ3; break; } } else if (ffd->st==GF_STREAM_AUDIO) { ffd->ctx->codec_type = CODEC_TYPE_AUDIO; switch (ffd->oti) { case 0x69: case 0x6B: ffd->ctx->frame_size = 1152; codec_id = CODEC_ID_MP2; break; } } else if ((ffd->st==GF_STREAM_ND_SUBPIC) && (ffd->oti==0xe0)) { codec_id = CODEC_ID_DVD_SUBTITLE; } ffd->codec = avcodec_find_decoder(codec_id); } /*should never happen*/ if (!ffd->codec) return GF_OUT_OF_MEM; /*setup MPEG-4 video streams*/ if ((ffd->st==GF_STREAM_VISUAL)) { /*for all MPEG-4 variants get size*/ if ((ffd->oti==0x20) || (ffd->oti == 0x21)) { if (!decSpecInfoSize || !decSpecInfo) return GF_NON_COMPLIANT_BITSTREAM; /*for regular MPEG-4, try to decode and if this fails try H263 decoder at first frame*/ if (ffd->oti==0x20) { e = gf_m4v_get_config(decSpecInfo, decSpecInfoSize, &dsi); if (e) return e; ffd->ctx->width = dsi.width; ffd->ctx->height = dsi.height; if (!dsi.width && !dsi.height) ffd->check_short_header = 1; ffd->previous_par = (dsi.par_num<<16) | dsi.par_den; ffd->no_par_update = 1; } else if (ffd->oti==0x21) { ffd->check_h264_isma = 1; } /*setup dsi for FFMPEG context BEFORE attaching decoder (otherwise not proper init)*/ ffd->ctx->extradata = malloc(sizeof(char)*decSpecInfoSize); memcpy(ffd->ctx->extradata, decSpecInfo, decSpecInfoSize); ffd->ctx->extradata_size = decSpecInfoSize; } ffd->frame = avcodec_alloc_frame(); } if (avcodec_open(ffd->ctx, ffd->codec)<0) return GF_NON_COMPLIANT_BITSTREAM; /*setup audio streams*/ if (ffd->st==GF_STREAM_AUDIO) { if ((ffd->codec->type == CODEC_ID_MP3LAME) || (ffd->codec->type == CODEC_ID_MP2)) { ffd->ctx->frame_size = (ffd->ctx->sample_rate > 24000) ? 1152 : 576; } /*may be 0 (cfg not known yet)*/ ffd->out_size = ffd->ctx->bits_per_sample * ffd->ctx->channels * ffd->ctx->frame_size / 8; if (!ffd->ctx->bits_per_sample) ffd->ctx->bits_per_sample = 16; if (!ffd->ctx->sample_rate) ffd->ctx->sample_rate = 44100; if (!ffd->ctx->channels) ffd->ctx->channels = 2; } else { switch (ffd->codec->id) { case CODEC_ID_MJPEG: case CODEC_ID_MJPEGB: case CODEC_ID_LJPEG: ffd->pix_fmt = GF_PIXEL_RGB_24; break; case CODEC_ID_DVD_SUBTITLE: ffd->frame = avcodec_alloc_frame(); avcodec_decode_video(ffd->ctx, ffd->frame, &gotpic, decSpecInfo, decSpecInfoSize); ffd->pix_fmt = GF_PIXEL_YV12; break; default: ffd->pix_fmt = GF_PIXEL_YV12; break; } ffd->out_size = ffd->ctx->width * ffd->ctx->height * 3; if (ffd->pix_fmt!=GF_PIXEL_RGB_24) ffd->out_size /= 2; }#if 0 ffd->ctx->debug = FF_DEBUG_PICT_INFO | FF_DEBUG_BITSTREAM | FF_DEBUG_STARTCODE; ffd->ctx->debug = 0xFFFFFFFF; av_log_set_level(AV_LOG_DEBUG); av_log_set_callback(gf_av_vlog);#endif return GF_OK;}static GF_Err FFDEC_DetachStream(GF_BaseDecoder *plug, u16 ES_ID){ FFDec *ffd = (FFDec *)plug->privateStack; if (!ffd->ES_ID) return GF_BAD_PARAM; ffd->ES_ID = 0; if (ffd->ctx) { if (ffd->ctx->extradata) free(ffd->ctx->extradata); avcodec_close(ffd->ctx); ffd->ctx = NULL; } return GF_OK;}static GF_Err FFDEC_GetCapabilities(GF_BaseDecoder *plug, GF_CodecCapability *capability){ FFDec *ffd = (FFDec *)plug->privateStack; /*base caps*/ switch (capability->CapCode) { /*ffmpeg seems quite reliable*/ case GF_CODEC_RESILIENT: capability->cap.valueInt = 1; return GF_OK; case GF_CODEC_PADDING_BYTES: capability->cap.valueInt = FF_INPUT_BUFFER_PADDING_SIZE; return GF_OK; case GF_CODEC_REORDER: capability->cap.valueInt = 1; return GF_OK; } if (!ffd->ctx) { capability->cap.valueInt = 0; return GF_OK; } /*caps valid only if stream attached*/ switch (capability->CapCode) { case GF_CODEC_OUTPUT_SIZE: capability->cap.valueInt = ffd->out_size; break; case GF_CODEC_SAMPLERATE: capability->cap.valueInt = ffd->ctx->sample_rate; break; case GF_CODEC_NB_CHAN: capability->cap.valueInt = ffd->ctx->channels; break; case GF_CODEC_BITS_PER_SAMPLE: capability->cap.valueInt = ffd->ctx->bits_per_sample; break; case GF_CODEC_BUFFER_MIN: capability->cap.valueInt = (ffd->st==GF_STREAM_AUDIO) ? 4 : 1; break; case GF_CODEC_BUFFER_MAX: /*for audio let the systems engine decide since we may have very large block size (1 sec with some QT movies)*/ capability->cap.valueInt = (ffd->st==GF_STREAM_AUDIO) ? 0 : 4; break; /*by default AAC access unit lasts num_samples (timescale being sampleRate)*/ case GF_CODEC_CU_DURATION: capability->cap.valueInt = (ffd->st==GF_STREAM_AUDIO) ? ffd->ctx->frame_size : 0; break; case GF_CODEC_WIDTH: capability->cap.valueInt = ffd->ctx->width; break; case GF_CODEC_HEIGHT: capability->cap.valueInt = ffd->ctx->height; break; case GF_CODEC_STRIDE: capability->cap.valueInt = (ffd->pix_fmt==GF_PIXEL_RGB_24) ? ffd->ctx->width*3 : ffd->ctx->width; break; case GF_CODEC_FPS: capability->cap.valueFloat = 30.0f; break; case GF_CODEC_PAR: capability->cap.valueInt = ffd->previous_par; break; case GF_CODEC_PIXEL_FORMAT: if (ffd->ctx->width) { capability->cap.valueInt = ffd->pix_fmt; } break; /*ffmpeg performs frame reordering internally*/ case GF_CODEC_REORDER: capability->cap.valueInt = 1; break; case GF_CODEC_WAIT_RAP: //ffd->ctx->hurry_up = 5; break; case GF_CODEC_CHANNEL_CONFIG: /*currently unused in ffmpeg*/ if (ffd->ctx->channels==1) { capability->cap.valueInt = GF_AUDIO_CH_FRONT_CENTER; } else { capability->cap.valueInt = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT; } break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -