当前位置: 首页 > news >正文

ffmpeg avio使用示例

源代码

ffmpeg 自定以输入输出avio从文件中读再写到另一个文件中的源码,ffmpeg 3.4

gcc ./test.c -o test -lpthread -lavformat -lavcodec -lavutil -lz

#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <stdio.h>
#include <stdlib.h>#define BUFFER_SIZE (32 * 1024)// 自定义上下文
typedef struct {FILE *input_file;FILE *output_file;
} CustomIOContext;// ========================================
// read_packet 回调:从输入文件读取数据
// ========================================
int read_packet(void *opaque, uint8_t *buf, int buf_size)
{CustomIOContext *ctx = (CustomIOContext *)opaque;size_t ret = fread(buf, 1, buf_size, ctx->input_file);if (ret == 0 && feof(ctx->input_file))return AVERROR_EOF;return ret; // 返回实际读取字节数
}// ========================================
// write_packet 回调:将数据写入输出文件
// ========================================
int write_packet(void *opaque, uint8_t *buf, int buf_size)
{CustomIOContext *ctx = (CustomIOContext *)opaque;size_t written = fwrite(buf, 1, buf_size, ctx->output_file);if (written != buf_size)return AVERROR(EIO); // 写入失败return written; // 返回成功写入字节数
}// ========================================
// seek_input: 输入文件的 seek 回调
// ========================================
int64_t seek_input(void *opaque, int64_t offset, int whence)
{CustomIOContext *ctx = (CustomIOContext *)opaque;// 处理特殊请求:获取文件大小if (whence == AVSEEK_SIZE) {long cur = ftell(ctx->input_file);if (cur == -1) return AVERROR(errno);if (fseek(ctx->input_file, 0, SEEK_END) < 0)return AVERROR(errno);long size = ftell(ctx->input_file);fseek(ctx->input_file, cur, SEEK_SET);  // 恢复原位置printf("seek input get file size %d\n", size);return size;}// 转换 FFmpeg 的 whence 到标准 C 的 whenceint std_whence;printf("seek input seek to %d\n", whence);switch (whence) {case SEEK_SET: std_whence = SEEK_SET; break;case SEEK_CUR: std_whence = SEEK_CUR; break;case SEEK_END: std_whence = SEEK_END; break;default: return AVERROR(EINVAL);}if (fseek(ctx->input_file, offset, std_whence) != 0)return AVERROR(errno);return ftell(ctx->input_file);
}// ========================================
// seek_output: 输出文件的 seek 回调
// ========================================
int64_t seek_output(void *opaque, int64_t offset, int whence)
{CustomIOContext *ctx = (CustomIOContext *)opaque;if (whence == AVSEEK_SIZE) {long cur = ftell(ctx->output_file);if (cur == -1) return AVERROR(errno);if (fseek(ctx->output_file, 0, SEEK_END) < 0)return AVERROR(errno);long size = ftell(ctx->output_file);fseek(ctx->output_file, cur, SEEK_SET);printf("seek output get file size %d\n", size);return size;}int std_whence;printf("seek output seek to %d\n", whence);switch (whence) {case SEEK_SET: std_whence = SEEK_SET; break;case SEEK_CUR: std_whence = SEEK_CUR; break;case SEEK_END: std_whence = SEEK_END; break;default: return AVERROR(EINVAL);}if (fseek(ctx->output_file, offset, std_whence) != 0)return AVERROR(errno);return ftell(ctx->output_file);
}int main(int argc, char *argv[])
{if (argc != 3) {fprintf(stderr, "Usage: %s <input_file> <output_file>\n", argv[0]);exit(1);}int ret = 0;const char *input_path  = argv[1];const char *output_path = argv[2];printf("read %s then write to %s\n", argv[1], argv[2]);av_register_all();avformat_network_init();AVFormatContext *ifmt_ctx = NULL;AVFormatContext *ofmt_ctx = NULL;CustomIOContext io_ctx = {0};// 打开输入文件io_ctx.input_file = fopen(input_path, "rb");if (!io_ctx.input_file) {perror("Cannot open input file");return -1;}// 打开输出文件io_ctx.output_file = fopen(output_path, "wb");if (!io_ctx.output_file) {perror("Cannot open output file");fclose(io_ctx.input_file);return -1;}// ================================// 设置输入 AVIOContext(用于读)// ================================unsigned char *input_buffer = av_malloc(BUFFER_SIZE);AVIOContext *avio_in = avio_alloc_context(input_buffer,           // 缓冲区BUFFER_SIZE,            // 缓冲区大小0,                      // 0=读模式,1=写模式&io_ctx,                // opaque 用户数据read_packet,            // read_callbackNULL,                   // write_callback(解复用不需要)seek_input                    // seek callback(可选));if (!avio_in) {fprintf(stderr, "Cannot allocate input AVIOContext\n");goto fail;}ifmt_ctx = avformat_alloc_context();if (!ifmt_ctx) {fprintf(stderr, "Cannot allocate input context\n");goto fail;}ifmt_ctx->pb = avio_in;ifmt_ctx->flags |= AVFMT_FLAG_CUSTOM_IO;// 创建输入格式上下文if ((ret = avformat_open_input(&ifmt_ctx, NULL, NULL, NULL)) < 0) {fprintf(stderr, "Cannot open input AVFormatContext ret %d\n", ret);goto fail;}if (avformat_find_stream_info(ifmt_ctx, NULL) < 0) {fprintf(stderr, "Cannot find stream info\n");goto fail;}// ================================// 设置输出 AVIOContext(用于写)// ================================unsigned char *output_buffer = av_malloc(BUFFER_SIZE);AVIOContext *avio_out = avio_alloc_context(output_buffer,          // 缓冲区BUFFER_SIZE,            // 缓冲区大小1,                      // 1=写模式&io_ctx,                // opaqueNULL,                   // read_packet(复用不需要)write_packet,           // write_callbackseek_output                    // seek(如果需要 seek 输出));if (!avio_out) {fprintf(stderr, "Cannot allocate output AVIOContext\n");goto fail;}// 创建输出格式上下文avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, argv[2]);if (!ofmt_ctx) {fprintf(stderr, "Cannot allocate output format context\n");goto fail;}ofmt_ctx->pb = avio_out;// 复制输入流到输出(简单拷贝流)for (int i = 0; i < ifmt_ctx->nb_streams; i++) {AVStream *in_stream = ifmt_ctx->streams[i];AVStream *out_stream = avformat_new_stream(ofmt_ctx, NULL);if (!out_stream) {fprintf(stderr, "Failed to create new stream\n");goto fail;}avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);out_stream->time_base = in_stream->time_base;}// 设置输出格式(自动检测基于文件名)ofmt_ctx->oformat = av_guess_format(NULL, output_path, NULL);if (!ofmt_ctx->oformat) {fprintf(stderr, "Cannot guess output format\n");goto fail;}// 打印信息av_dump_format(ifmt_ctx, 0, input_path, 0);av_dump_format(ofmt_ctx, 0, output_path, 1);#if 1AVDictionary *opts = NULL;
#if 0//mp4av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);avformat_write_header(ofmt_ctx, &opts);
#else//flvav_dict_set(&opts, "flv_metadata", "0", 0);        // 必须关闭av_dict_set(&opts, "flvflags", "no_duration_filesize", 0); // 显式关闭
#endif// 写文件头if (avformat_write_header(ofmt_ctx, &opts) < 0) {fprintf(stderr, "Error writing header\n");goto fail;}
#else// 写文件头if (avformat_write_header(ofmt_ctx, NULL) < 0) {fprintf(stderr, "Error writing header\n");goto fail;}
#endifAVPacket pkt;av_init_packet(&pkt);pkt.data = NULL;pkt.size = 0;// ==============// 开始转封装// ==============while (av_read_frame(ifmt_ctx, &pkt) >= 0) {// 修改鏃????戳(避免负值)AVStream *in_stream = ifmt_ctx->streams[pkt.stream_index];AVStream *out_stream = ofmt_ctx->streams[pkt.stream_index];pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base,AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base,AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX);pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);pkt.pos = -1;// 写包if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) {fprintf(stderr, "Error muxing packet\n");break;}av_packet_unref(&pkt);}// 写文浠????(如有必要)av_write_trailer(ofmt_ctx);
fail:// 清理资源printf("clear input resource\n");if (ifmt_ctx) {avformat_close_input(&ifmt_ctx);}printf("clear output resource\n");if (ofmt_ctx) {if (ofmt_ctx->pb) {av_freep(&ofmt_ctx->pb->buffer);avio_context_free(&ofmt_ctx->pb);}avformat_free_context(ofmt_ctx);}printf("close files\n");if (io_ctx.input_file) fclose(io_ctx.input_file);if (io_ctx.output_file) fclose(io_ctx.output_file);printf("Done.\n");return 0;
}

源码分析

write 和 read和seek 回调的调用时机如何

实际情况write回调并不是以packt为单位的写入,回调中的buf的缓存情况如何

http://www.dtcms.com/a/469294.html

相关文章:

  • 我把Excel变成了像素画板!用Python实现图片到单元格的映射
  • Android相册高频面试场景分析
  • 郑州建筑公司网站建设网页制作标准
  • iOS 推送证书 P8 介绍及生成流程
  • Ubuntu22.04安装Ibus的中文输入法
  • 基于STM32的智能物联网加湿器/智能家居
  • 23种设计模式——解释器模式(Interpreter Pattern)
  • 贴吧网站建设个人免费空间申请
  • 机器人能否实现远程视频通话方便家属探视老人
  • 小杰深度学习(ten)——视觉-经典神经网络——LetNet
  • LeetCode每日一题——困于环中的机器人
  • c++11 列表初始化 右值引用 移动语义 引用折叠 完美转发
  • 以太网与工业以太网通信C#开发
  • 14-verilog的SPI主驱动
  • vue项目安装chromedriver超时解决办法
  • 【C++】12.多态(超详解)
  • 【Linux操作系统】进程控制
  • 做实验流程图的网站广州免费核酸采集点时间
  • 网站网页设计公司电子商务公司logo
  • 潮玩盲盒抽赏小程序玩法拆解:不同视角下的增长逻辑分析
  • 使用Milvus和DeepSeek构建RAG demo
  • WD5030A,24V降5V,15A 大电流,应用于手机、平板、笔记本充电器
  • wordpress 新浪微博百度网站优化外包
  • Oracle LOB使用入门和简单使用,提供学习用的测试用例!
  • Java版旅游系统/文旅系统/旅游助手/旅游攻略/公众号/小程序/app全套源码
  • 线程2---javaEE(校招)
  • [创业之路-687]:华为“1+8+N”战略以及其背后的技术栈、商业逻辑。
  • 基于大语言模型(LLM)的城市时间、空间与情感交织分析:面向智能城市的情感动态预测与空间优化
  • 眼控交互:ErgoLAB新一代人机交互方式
  • 数字货币众筹网站开发如何做高网站的浏览量