音视频开发——FFmpeg 实现MP4转FLV文件 C语言实现

文章目录

转换步骤

  1. 初始化FFmpeg库
  2. 打开输入文件
  3. 找到输入文件的流信息
  4. 打开输出文件并设置输出格式
  5. 创建输出文件的流
  6. 初始化解码器和编码器
  7. 读取输入文件的帧并写入输出文件
  8. 释放资源

关键代码

1 初始化FFmpeg库

c 复制代码
av_register_all();
  1. 打开输入文件

    c 复制代码
    if ((ret = avformat_open_input(&input_format_ctx, input_filename, NULL, NULL)) < 0) {
        fprintf(stderr, "Could not open input file '%s'\n", input_filename);
        return ret;
    }
  2. 找到输入文件的流信息

    c 复制代码
    if ((ret = avformat_find_stream_info(input_format_ctx, NULL)) < 0) {
        fprintf(stderr, "Failed to retrieve input stream information\n");
        return ret;
    }
  3. 打开输出文件并设置输出格式

    c 复制代码
    avformat_alloc_output_context2(&output_format_ctx, NULL, "flv", output_filename);
    if (!output_format_ctx) {
        fprintf(stderr, "Could not create output context\n");
        return AVERROR_UNKNOWN;
    }
  4. 创建输出文件的流

    c 复制代码
    for (int i = 0; i < input_format_ctx->nb_streams; i++) {
        AVStream *in_stream = input_format_ctx->streams[i];
        AVStream *out_stream = avformat_new_stream(output_format_ctx, NULL);
        if (!out_stream) {
            fprintf(stderr, "Failed to allocate output stream\n");
            return AVERROR_UNKNOWN;
        }
        // 复制输入流的编解码器参数到输出流
        if ((ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar)) < 0) {
            fprintf(stderr, "Failed to copy codec parameters\n");
            return ret;
        }
        out_stream->codecpar->codec_tag = 0;
    }
  5. 打开输出文件

    c 复制代码
    if (!(output_format_ctx->oformat->flags & AVFMT_NOFILE)) {
        if ((ret = avio_open(&output_format_ctx->pb, output_filename, AVIO_FLAG_WRITE)) < 0) {
            fprintf(stderr, "Could not open output file '%s'\n", output_filename);
            return ret;
        }
    }
  6. 写文件头

    c 复制代码
    if ((ret = avformat_write_header(output_format_ctx, NULL)) < 0) {
        fprintf(stderr, "Error occurred when opening output file\n");
        return ret;
    }
  7. 读取输入文件的帧并写入输出文件

c 复制代码
while (1) {
    AVStream *in_stream, *out_stream;

    ret = av_read_frame(input_format_ctx, &packet);
    if (ret < 0)
        break;

    in_stream  = input_format_ctx->streams[packet.stream_index];
    out_stream = output_format_ctx->streams[packet.stream_index];

    log_packet(input_format_ctx, &packet, "in");

    packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
    packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
    packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
    packet.pos = -1;

    log_packet(output_format_ctx, &packet, "out");

    ret = av_interleaved_write_frame(output_format_ctx, &packet);
    if (ret < 0) {
        fprintf(stderr, "Error muxing packet\n");
        break;
    }

    av_packet_unref(&packet);
}
  1. 写文件尾

    c 复制代码
    av_write_trailer(output_format_ctx);
  2. 释放资源

    c 复制代码
    avformat_close_input(&input_format_ctx);
    
    if (output_format_ctx && !(output_format_ctx->oformat->flags & AVFMT_NOFILE))
        avio_closep(&output_format_ctx->pb);
    
    avformat_free_context(output_format_ctx);

通过以上步骤和代码,可以将MP4文件转换为FLV格式。

完整代码

c 复制代码
#include <stdio.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libavutil/timestamp.h>
#include <libswscale/swscale.h>

void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
{
    AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;

    printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
           tag,
           av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
           av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
           av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
           pkt->stream_index);
}

int main(int argc, char *argv[])
{
    if (argc < 3) {
        printf("Usage: %s <input file> <output file>\n", argv[0]);
        return -1;
    }

    const char *input_filename = argv[1];
    const char *output_filename = argv[2];

    AVFormatContext *input_format_ctx = NULL, *output_format_ctx = NULL;
    AVPacket packet;
    int ret;

    av_register_all();

    // 打开输入文件
    if ((ret = avformat_open_input(&input_format_ctx, input_filename, NULL, NULL)) < 0) {
        fprintf(stderr, "Could not open input file '%s'\n", input_filename);
        return ret;
    }

    // 找到输入文件的流信息
    if ((ret = avformat_find_stream_info(input_format_ctx, NULL)) < 0) {
        fprintf(stderr, "Failed to retrieve input stream information\n");
        return ret;
    }

    // 打开输出文件并设置输出格式
    avformat_alloc_output_context2(&output_format_ctx, NULL, "flv", output_filename);
    if (!output_format_ctx) {
        fprintf(stderr, "Could not create output context\n");
        return AVERROR_UNKNOWN;
    }

    // 创建输出文件的流
    for (int i = 0; i < input_format_ctx->nb_streams; i++) {
        AVStream *in_stream = input_format_ctx->streams[i];
        AVStream *out_stream = avformat_new_stream(output_format_ctx, NULL);
        if (!out_stream) {
            fprintf(stderr, "Failed to allocate output stream\n");
            return AVERROR_UNKNOWN;
        }

        // 复制输入流的编解码器参数到输出流
        if ((ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar)) < 0) {
            fprintf(stderr, "Failed to copy codec parameters\n");
            return ret;
        }
        out_stream->codecpar->codec_tag = 0;
    }

    // 打开输出文件
    if (!(output_format_ctx->oformat->flags & AVFMT_NOFILE)) {
        if ((ret = avio_open(&output_format_ctx->pb, output_filename, AVIO_FLAG_WRITE)) < 0) {
            fprintf(stderr, "Could not open output file '%s'\n", output_filename);
            return ret;
        }
    }

    // 写文件头
    if ((ret = avformat_write_header(output_format_ctx, NULL)) < 0) {
        fprintf(stderr, "Error occurred when opening output file\n");
        return ret;
    }

    // 读取输入文件的帧并写入输出文件
    while (1) {
        AVStream *in_stream, *out_stream;

        // 获取一个packet
        ret = av_read_frame(input_format_ctx, &packet);
        if (ret < 0)
            break;

        in_stream  = input_format_ctx->streams[packet.stream_index];
        out_stream = output_format_ctx->streams[packet.stream_index];

        // 记录packet的时间戳
        log_packet(input_format_ctx, &packet, "in");

        // 转换PTS/DTS
        packet.pts = av_rescale_q_rnd(packet.pts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
        packet.dts = av_rescale_q_rnd(packet.dts, in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
        packet.duration = av_rescale_q(packet.duration, in_stream->time_base, out_stream->time_base);
        packet.pos = -1;

        // 记录packet的时间戳
        log_packet(output_format_ctx, &packet, "out");

        // 写packet到输出文件
        ret = av_interleaved_write_frame(output_format_ctx, &packet);
        if (ret < 0) {
            fprintf(stderr, "Error muxing packet\n");
            break;
        }

        av_packet_unref(&packet);
    }

    // 写文件尾
    av_write_trailer(output_format_ctx);

    // 释放资源
    avformat_close_input(&input_format_ctx);

    if (output_format_ctx && !(output_format_ctx->oformat->flags & AVFMT_NOFILE))
        avio_closep(&output_format_ctx->pb);

    avformat_free_context(output_format_ctx);

    return 0;
}
相关推荐
美狐美颜sdk36 分钟前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
melonbo4 小时前
使用FFmpeg将H.264码流封装为MP4
ffmpeg·音视频·h.264
aqi006 小时前
FFmpeg开发笔记(七十七)Android的开源音视频剪辑框架RxFFmpeg
android·ffmpeg·音视频·流媒体
森焱森7 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
慢行的骑兵8 小时前
Android音视频探索之旅 | CMake基础语法 && 创建支持Ffmpeg的Android项目
ffmpeg·音视频
Just_Paranoid8 小时前
华为云Flexus+DeepSeek征文|基于Dify构建音视频内容转录工作流
华为云·音视频·dify·maas·deepseek·flexusx
go54631584659 小时前
修改Spatial-MLLM项目,使其专注于无人机航拍视频的空间理解
人工智能·算法·机器学习·架构·音视频·无人机
小林C语言10 小时前
C语言 | 判断是否为回文数
c语言
叹一曲当时只道是寻常12 小时前
Softhub软件下载站实战开发(十):实现图片视频上传下载接口
golang·go·音视频
myloveasuka13 小时前
信号操作集函数
linux·运维·服务器·c语言·c++·vscode