音视频

ffmpeg_sample解读_avio_reading

2020-10-21  本文已影响0人  刘佳阔

title: ffmpeg_sample解读_avio_reading
date: 2020-10-21 10:15:02
tags: [读书笔记]
typora-copy-images-to: ./imgs
typora-root-url: ./imgs


概括

Ffmpeg 项目中的 实例解读. 把他移到安卓项目中来开发了.

这个项目是读取 文件.解码出文件信息.

使用方式 使用 ./avio_reading 1.mp4 读入文件

输出如下

ptr:0x10e1b9000 size:23014356
ptr:0x10e1ba000 size:23010260
ptr:0x10e1bb000 size:23006164
ptr:0x10e1bce2a size:22998442
ptr:0x10e1bde2a size:22994346
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '1.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isomavc1
    creation_time   : 2013-05-03T22:51:07.000000Z
  Duration: 00:00:46.61, start: 0.000000, bitrate: N/A
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 960x400 [SAR 1:1 DAR 12:5], 3859 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
    Metadata:
      creation_time   : 2013-05-03T22:50:47.000000Z
      handler_name    : GPAC ISO Video Handler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo立体生, fltp, 92 kb/s (default)
    Metadata:
      creation_time   : 2013-05-03T22:51:07.000000Z
      handler_name    : GPAC ISO Audio Handler

这个源码相对简单.就直接看注释就行了


/**
 * @file
 * libavformat AVIOContext API example.
 *
 * Make libavformat demuxer access media content through a custom
 * AVIOContext read callback.
 * @example avio_reading.c
 */

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/file.h>
#include "../macro.h"


/**
 * 使用   ./avio_reading 1.mp4 读入文件 解码出文件信息
 * ptr:0x10e1b9000 size:23014356
ptr:0x10e1ba000 size:23010260
ptr:0x10e1bb000 size:23006164
ptr:0x10e1bce2a size:22998442
ptr:0x10e1bde2a size:22994346
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '1.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 1
    compatible_brands: isomavc1
    creation_time   : 2013-05-03T22:51:07.000000Z
  Duration: 00:00:46.61, start: 0.000000, bitrate: N/A
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 960x400 [SAR 1:1 DAR 12:5], 3859 kb/s, 23.98 fps, 23.98 tbr, 24k tbn, 47.95 tbc (default)
    Metadata:
      creation_time   : 2013-05-03T22:50:47.000000Z
      handler_name    : GPAC ISO Video Handler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo立体生, fltp, 92 kb/s (default)
    Metadata:
      creation_time   : 2013-05-03T22:51:07.000000Z
      handler_name    : GPAC ISO Audio Handler
 */
struct buffer_data {
    uint8_t *ptr;
    size_t size; ///< size left in the buffer
};

//把 opaque(也就是bd) 中的数据拷贝到 buf中,bd的数据就是读取的文件的数据
//猜测这个buf 应该是 avioContext 内部的buf
static int read_packet(void *opaque, uint8_t *buf, int buf_size) {
    struct buffer_data *bd = (struct buffer_data *) opaque;
    buf_size = FFMIN(buf_size, bd->size);

    if (!buf_size)
        return AVERROR_EOF;
    LOGE("ptr:%p size:%zu\n", bd->ptr, bd->size);

    /* copy internal buffer data to buf */
    //从bd 拷贝到buf中. 每次拷贝buf_size个
    memcpy(buf, bd->ptr, buf_size);
    bd->ptr += buf_size;
    bd->size -= buf_size;

    return buf_size;
}

int reading_main(int argc, char *argv[]) {
    AVFormatContext *fmt_ctx = NULL;
    AVIOContext *avio_ctx = NULL;
    uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
    //size_t可能会提高代码的可移植性、有效性或者可读 无符号整形
    size_t buffer_size, avio_ctx_buffer_size = 4096;
    char *input_filename = NULL;
    int ret = 0;
    struct buffer_data bd = {0};


    for (int i = 0; i < argc; ++i) {
        LOGE("paramets is %s",argv[i]);
    }
    if (argc != 2) {
        LOGE("usage: %s input_file\n API example program to show how to read from a custom buffer accessed through AVIOContext."
        ,argv[0]);


        return 1;
    }
    input_filename = argv[1];

    /* slurp file content into buffer */
    //读取文件.写入到buff中,buffer_size指明大小 --buf里没数据.只是分配了空间,建立buffer和文件的映射
    ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
    if (ret < 0)
        goto end;

    //把读取的数据封装到bd结构中, 此时buf 中还没数据.
    /* fill opaque structure used by the AVIOContext read callback */
    bd.ptr = buffer;
    bd.size = buffer_size;

    //初始化格式上下文
    if (!(fmt_ctx = avformat_alloc_context())) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    //分配一个buffer,具有合适的对齐格式,4096字节大小.此时avio_ctx_buffer 也是空
    avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
    if (!avio_ctx_buffer) {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    //分配io读写上下文 回调是read_packet   0表示从buffer中读数据
    //相当于就是可以通过avio_ctx  从 bd 里读去数据,会回调read_packet方法
    avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
                                  0, &bd, &read_packet, NULL, NULL);
    if (!avio_ctx) {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    fmt_ctx->pb = avio_ctx;

    //打开 输入流,读取数据.这里才是从bd中把数据写入到avio_ctx_buffer中.回调read_packet 函数
    ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
    if (ret < 0) {
        LOGE(stderr, "Could not open input\n");
        goto end;
    }

    // 找到数据中的流信息,此时数据已经都写到 avoiContext中了,
    ret = avformat_find_stream_info(fmt_ctx, NULL);
    if (ret < 0) {
        LOGE(stderr, "Could not find stream information\n");
        goto end;
    }

    //打印数据文件信息
    av_dump_format(fmt_ctx, 0, input_filename, 0);

    end:
    //关闭上下文
    avformat_close_input(&fmt_ctx);

    /* note: the internal buffer could have changed, and be != avio_ctx_buffer */
    if (avio_ctx)//是否内部buffer及io上下问
        av_freep(&avio_ctx->buffer);
    avio_context_free(&avio_ctx);

    av_file_unmap(buffer, buffer_size);

    if (ret < 0) {
        LOGE(stderr, "Error occurred: %s\n", av_err2str(ret));
        return 1;
    }

    return 0;
}

上一篇下一篇

猜你喜欢

热点阅读