FFmpeg 简单实现转码

本文详细介绍了视频转码的全过程,包括解封装、解码、编码、封装及音频重采样,提供关键代码片段,适合初学者理解FFmpeg核心结构和操作。

首发地址,会更错

本文汇总前面几篇文章,把所有流程合并到一块,简单实现转码的流程。其中有些异常不做处理。

转码原理

先看雷神的一张图:

上图描述的很明白,上完图发现已经不需要语言描述了[Dog]。 但还是画个来说明一下这块之间的联系:

其中,AVFormatContext、AVPacket等重要的结构体请看:FFmpeg重要结构体(转自雷神)

代码实现

/**
 * @author 秦城季
 * @email xhunmon@126.com
 * @Blog https://qincji.gitee.io
 * @date 2021/01/08
 * description: 转码
 * 主要思路:
 * 格式1-->解封装--[解封装数据AVPacket]-->解码--[原始数据AVFrame]-->编码-->[编码后数据AVPacket]-->封装-->格式2
 *
 * 2021/01/11 增加音频重采样变换
 * <br>
 */
#include <stdint.h>
#include <stdio.h>

extern "C" {
   
   
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>

#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/frame.h>
#include <libavutil/samplefmt.h>

#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libswresample/swresample.h>
}

int main(int argc, char **argv) {
   
   
//    const char *in_filename = "source/lol.mp4";
//    const char *out_filename = "output/lol.wma";
//    const char *in_filename = "source/Kobe.flv";
//    const char *out_filename = "output/Kobe.avi";
//    const char *in_filename = "source/lol.mp4";
//    const char *out_filename = "output/lol.avi";
    const char *in_filename = "source/Kobe.flv";
    const char *out_filename = "output/Kobe2.avi";
    remove(out_filename);

    SwrContext *swr_ctx;//当有需要时,需要重采样
    AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
    AVPacket *ipkt = NULL, *opkt = NULL;
    AVFrame *iframe = NULL, *oframe_a = NULL;
    AVCodecContext *ic_v = NULL, *ic_a = NULL, *oc_v = NULL, *oc_a = NULL;
    AVCodec *ocodec_v = NULL, *ocodec_a = NULL;
    int iindex_v = -1, iindex_a = -1, oindex_v = -1, oindex_a = -1, ret, dst_nb_samples;

    ipkt = av_packet_alloc();
    opkt = av_packet_alloc();

    /**(解封装 1.1):创建并初始化AVFormatContext*/
    if (avformat_open_input(&ifmt_ctx, in_filename, NULL, NULL) < 0) {
   
   
        fprintf(stderr, "Could not open source file %s\n", in_filename);
        goto end;
    }
    /**(解封装 1.2):检索流信息,这个过程会检查输入流中信息是否存在异常*/
    if (avformat_find_stream_info(ifmt_ctx, NULL) < 0) {
   
   
        fprintf(stderr, "Could not find stream information\n");
        goto end;
    }
    /**(解封装 1.3):查找视频和音频的下标*/
    if ((iindex_v = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0)) < 0) {
   
   
        fprintf(stderr, "Could not find video stream\n");
        goto end;
    }
    if ((iindex_a = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0)) < 0) {
   
   
        fprintf(stderr, "Could not find video stream\n");
        goto end;
    }

    /**(解码 2.1):解码器直接从AVFormatContext对象的流中获取,然后指定该解码器的AVCodec*/
    ic_v = ifmt_ctx->streams[iindex_v]->codec;
    if (!(ic_v->codec = avcodec_find_decoder(ic_v->codec_id))
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值