IT评测·应用市场-qidao123.com技术社区

标题: 【音视频】AVIO输入模式 [打印本页]

作者: 何小豆儿在此    时间: 3 天前
标题: 【音视频】AVIO输入模式
内存IO模式
  1. AVIOContext *avio_alloc_context(
  2. unsigned char *buffer,
  3. int buffer_size,
  4. int write_flag,
  5. void *opaque,
  6. int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
  7. int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
  8. int64_t (*seek)(void *opaque, int64_t offset, int whence)
  9. );
复制代码
参数阐明:

一、avio_alloc_context 的环形缓冲本质

avio_alloc_context 创建的 AVIOContext 结构体 内部维护了一个环形缓冲区,其焦点特性包括:
实现流程

准备文件

在build路径下准备相干mp3和aac文件

添加main函数参数,表示输入文件和输出文件

打开文件

使用FILE二进制打开输入文件和输出文件
  1. const char *in_file_name = argv[1];
  2. const char *out_file_name = argv[2];
  3. FILE *in_file = NULL;
  4. FILE *out_file = NULL;
  5.         // 1. 打开参数文件
  6. in_file = fopen(in_file_name, "rb");
  7. if(!in_file) {
  8.         printf("open file %s failed\n", in_file_name);
  9.         return  -1;
  10. }
  11. out_file = fopen(out_file_name, "wb");
  12. if(!out_file) {
  13.         printf("open file %s failed\n", out_file_name);
  14.         return  -1;
  15. }
复制代码
自定义IO读取


  1.   uint8_t *io_buffer = av_malloc(BUF_SIZE);
  2. AVIOContext *avio_ctx = avio_alloc_context(io_buffer, BUF_SIZE, 0, (void *)in_file,    \
  3.                                                                                    read_packet, NULL, NULL);
  4. AVFormatContext *format_ctx = avformat_alloc_context();
  5. format_ctx->pb = avio_ctx;
  6. int ret = avformat_open_input(&format_ctx, NULL, NULL, NULL);
  7. if(ret < 0) {
  8.         printf("avformat_open_input failed:%s\n", av_err2str(ret));
  9.         return -1;
  10. }
复制代码
read_packet回调函数
  1. static int read_packet(void *opaque, uint8_t *buf, int buf_size)
  2. {
  3.     FILE *in_file = (FILE *)opaque;
  4.     int read_size = fread(buf, 1, buf_size, in_file);
  5.     // printf("read_packet read/*_*/size:%d, buf_size:%d\n", read_size, buf_size);
  6.     if(read_size <=0) {
  7.         return AVERROR_EOF;     // 数据读取完毕
  8.     }
  9.     return read_size;
  10. }
复制代码
查找解码器


  1. AVCodecContext *codec_ctx = avcodec_alloc_context3(codec);
  2. if(!codec_ctx) {
  3.         printf("avcodec_alloc_context3 failed\n");
  4.         return -1;
  5. }
  6. ret = avcodec_open2(codec_ctx, codec, NULL);
  7. if(ret < 0) {
  8.         printf("avcodec_open2 failed:%s\n", av_err2str(ret));
  9.         return -1;
  10. }
复制代码
解码并写入文件


  1. AVPacket *packet = av_packet_alloc();
  2. ret = av_read_frame(format_ctx, packet);
复制代码

  1. ret = avcodec_send_packet(dec_ctx, packet);
复制代码

  1. ret = avcodec_receive_frame(dec_ctx, frame);
复制代码

  1. int data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);
  2. for(int i = 0; i < frame->nb_samples; i++) {
  3. for(int ch = 0; ch < dec_ctx->channels; ch++) {
  4.         fwrite(frame->data[ch] + data_size *i, 1, data_size, outfile);
  5.         }
  6. }
复制代码

  1. while (1) {
  2.         ret = av_read_frame(format_ctx, packet);
  3.         if(ret < 0) {
  4.                 printf("av_read_frame failed:%s\n", av_err2str(ret));
  5.                 break;
  6.         }
  7.         decode(codec_ctx, packet, frame, out_file);
  8. }
复制代码
decode函数
  1. static void decode(AVCodecContext *dec_ctx, AVPacket *packet, AVFrame *frame,                   FILE *outfile){    int ret = 0;    ret = avcodec_send_packet(dec_ctx, packet);
  2.     if(ret == AVERROR(EAGAIN)) {        printf("Receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");    } else if(ret < 0) {        printf("Error submitting the packet to the decoder, err:%s\n",               av_get_err(ret));        return;    }    while (ret >= 0) {        ret = avcodec_receive_frame(dec_ctx, frame);
  3.         if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {            return;        } else if (ret < 0)  {            printf("Error during decoding\n");            exit(1);        }        if(!packet) {            printf("get flush frame\n");        }        int data_size = av_get_bytes_per_sample(dec_ctx->sample_fmt);        //        print_sample_format(frame);        /**           P表示Planar(平面),其数据格式分列方式为 :           LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每个LLLLLLRRRRRR为一个音频帧)           而不带P的数据格式(即交织分列)分列方式为:           LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每个LR为一个音频样本)        播放范例:   ffplay -ar 48000 -ac 2 -f f32le believe.pcm            并不是每一种都是这样的格式        */        // 这里的写法不是通用,通用要调用重采样的函数去实现        // 这里只是针对解码出来是planar格式的转换        for(int i = 0; i < frame->nb_samples; i++) {            for(int ch = 0; ch < dec_ctx->channels; ch++) {                fwrite(frame->data[ch] + data_size *i, 1, data_size, outfile);            }        }    }}
复制代码
冲刷解码器


  1. decode(codec_ctx, NULL, frame, out_file);
复制代码
竣事利用

退出之前要开释内存、关闭文件
  1. fclose(in_file);
  2. fclose(out_file);
  3. av_free(io_buffer);
  4. av_frame_free(frame);
  5. av_packet_free(packet);
  6. avformat_close_input(&format_ctx);
  7. avcodec_free_context(&codec_ctx);
复制代码
更多资料:https://github.com/0voice

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4