AVFormatContext协议层:理论与实战(三)

简介: AVFormatContext协议层:理论与实战(三)

AVFormatContext协议层:理论与实战(二)https://developer.aliyun.com/article/1473890


五、avio 实战 3:自定义数据来源

avio 自定义数据来源:可以是文件, 可以是内存, 可以是网络

本次实战的在实战 2 的基础上自定义了数据来源,即使用内存映射技术将输入视频文件映射到内存中。参考了 ffmepg 官方提供的测试用例avio_read_callback.c

1、示例源码

/**
 * @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>
//自定义缓冲区
struct buffer_data {
    uint8_t *ptr;
    size_t size; ///< size left in the buffer
};
//读取数据(回调函数)
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;
    printf("ptr:%p size:%d\n", bd->ptr, bd->size);
    /* copy internal buffer data to buf */
    /// 灵活应用[内存buf]:读取的是内存,比如:加密播放器,这里解密
    memcpy(buf, bd->ptr, buf_size);
    bd->ptr  += buf_size;
    bd->size -= buf_size;
    return buf_size;
}
int main(int argc, char *argv[])
{
    AVFormatContext *fmt_ctx = NULL;
    AVIOContext *avio_ctx = NULL;
    uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
    size_t buffer_size, avio_ctx_buffer_size = 4096;
    char *input_filename = NULL;
    int ret = 0;
    struct buffer_data bd = { 0 };
    printf("Hello,ffmpeg\n");
    input_filename = "./debug/test.mp4";
    /* slurp file content into buffer */
    ///内存映射文件
    ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
    if (ret < 0)
        goto end;
    printf("av_file_map,ok\n");
    /* fill opaque structure used by the AVIOContext read callback */
    bd.ptr  = buffer;
    bd.size = buffer_size;
    /// 创建对象:AVFormatContext
    if (!(fmt_ctx = avformat_alloc_context())) {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    printf("avformat_alloc_context,ok\n");
    /// 分配内存
    avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
    if (!avio_ctx_buffer) {
        ret = AVERROR(ENOMEM);
        goto end;
    }
    /// 创建对象:AVIOContext,注意参数
    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;
    printf("avio_alloc_context,ok\n");
    /// 打开输入流
    ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not open input\n");
        goto end;
    }
    printf("avformat_open_input,ok\n");
    /// 查找流信息
    ret = avformat_find_stream_info(fmt_ctx, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not find stream information\n");
        goto end;
    }
    printf("avformat_find_stream_info,ok\n");
    printf("******nb_streams=%d\n",fmt_ctx->nb_streams);
    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)
        av_freep(&avio_ctx->buffer);
    avio_context_free(&avio_ctx);
    /// 内存映射文件:解绑定
    av_file_unmap(buffer, buffer_size);
    if (ret < 0) {
        fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
        return 1;
    }
    return 0;
}
  • av_file_map():读取文件,并将其内容放入新分配的缓冲区中。返回的缓冲区必须使用 av_file_unmap() 释放;
  • av_dump_format():它用于打印关于音频或视频文件格式的详细信息,例如有关音频或视频文件的格式、流和编解码器的详细信息。包括文件格式、编解码器信息、流参数和元数据等;

2、运行结果

Hello,ffmpeg
av_file_map,ok
avformat_alloc_context,ok
avio_alloc_context,ok
ptr:04650000 size:1247737
....
ptr:04780000 size:2553
avformat_open_input,ok
avformat_find_stream_info,ok
******nb_streams=2
[mov,mp4,m4a,3gp,3g2,mj2 @ 01eb0c40] stream 0, offset 0x30: partial file
[mov,mp4,m4a,3gp,3g2,mj2 @ 01eb0c40] Could not find codec parameters for stream 0 (Video: h264 (avc1 / 0x31637661), none, 1280x720, 1638 kb/s): unspecified pixel format
Consider increasing the value for the 'analyzeduration' and 'probesize' options
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from './debug/output.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf60.3.100
  Duration: 00:00:05.00, start: 0.000000, bitrate: N/A
    Stream #0:0(und): Video: h264 (avc1 / 0x31637661), none, 1280x720, 1638 kb/s, SAR 1:1 DAR 16:9, 25 fps, 25 tbr, 12800 tbn, 25600 tbc (default)
    Metadata:
      handler_name    : VideoHandler
      encoder         : Lavc60.3.100 libx264
    Stream #0:1(und): Audio: aac (mp4a / 0x6134706D), 48000 Hz, 5.1, fltp, 348 kb/s (default)
    Metadata:
      handler_name    : SoundHandler
目录
相关文章
|
1月前
|
存储 缓存 编解码
AVFormatContext封装层:理论与实战(一)
AVFormatContext封装层:理论与实战(一)
33 1
|
1月前
|
编解码 算法 容器
AVFormatContext封装层:理论与实战(二)
AVFormatContext封装层:理论与实战(二)
30 0
|
8月前
|
XML 存储 JSON
【面试题精讲】序列化协议对应于 TCP/IP 4 层模型的哪一层?
【面试题精讲】序列化协议对应于 TCP/IP 4 层模型的哪一层?
|
1月前
|
大数据 测试技术 API
AVFormatContext协议层:理论与实战(一)
AVFormatContext协议层:理论与实战(一)
20 0
|
1月前
|
编解码 内存技术
AVFormatContext编解码层:理论与实战(三)
AVFormatContext编解码层:理论与实战(三)
24 0
|
1月前
|
编解码 缓存 大数据
AVFormatContext编解码层:理论与实战(一)
AVFormatContext编解码层:理论与实战(一)
42 0
|
1月前
|
编解码
AVFormatContext编解码层:理论与实战(二)
AVFormatContext编解码层:理论与实战(二)
30 0
|
22天前
|
缓存
计算机网络——数据链路层-可靠传输的实现机制:选择重传协议SR(介绍、工作原理、窗口尺寸、题目练习)
计算机网络——数据链路层-可靠传输的实现机制:选择重传协议SR(介绍、工作原理、窗口尺寸、题目练习)
21 0
|
1月前
|
编解码 内存技术
AVFormatContext封装层:理论与实战(三)
AVFormatContext封装层:理论与实战(三)
15 1
AVFormatContext封装层:理论与实战(三)
|
1月前
|
测试技术
AVFormatContext协议层:理论与实战(二)
AVFormatContext协议层:理论与实战(二)
19 1