FFMPEG内存操作(一) avio_reading.c 回调读取数据到内存解析

相关博客列表 :

    FFMPEG内存操作(一) avio_reading.c 回调读取数据到内存解析 

    FFMPEG内存操作(二)从内存中读取数及数据格式的转换 

    FFmpeg内存操作(三)内存转码器

   在FFMPEG的官方例程中,有个avio_reading.c 的文件,他的主要功能是将音视频文件读取到内存,如果FFMPEG需要使用输入文件的数据,则直接从内存中调用。初学FFMPEG,给avio_reading.c 文件做了一个注释,如果不对,欢迎指正。

[objc] view plain copy
 
 print?
  1. /* 
  2.  * Copyright (c) 2014 Stefano Sabatini 
  3.  * 
  4.  * Permission is hereby granted, free of charge, to any person obtaining a copy 
  5.  * of this software and associated documentation files (the "Software"), to deal 
  6.  * in the Software without restriction, including without limitation the rights 
  7.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
  8.  * copies of the Software, and to permit persons to whom the Software is 
  9.  * furnished to do so, subject to the following conditions: 
  10.  * 
  11.  * The above copyright notice and this permission notice shall be included in 
  12.  * all copies or substantial portions of the Software. 
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
  15.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
  16.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
  17.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
  18.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
  19.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
  20.  * THE SOFTWARE. 
  21.  */  
  22.   
  23. /** 
  24.  * @file 
  25.  * libavformat AVIOContext API example. 
  26.  * 
  27.  * Make libavformat demuxer access media content through a custom 
  28.  * AVIOContext read callback. 
  29.  * @example avio_reading.c 
  30.  */  
  31.   
  32. #include <libavcodec/avcodec.h>  
  33. #include <libavformat/avformat.h>  
  34. #include <libavformat/avio.h>  
  35. #include <libavutil/file.h>  
  36.   
  37. struct buffer_data {  
  38.     uint8_t *ptr; /* 文件中对应位置指针 */  
  39.     size_t size; ///< size left in the buffer /* 文件当前指针到末尾 */   
  40. };  
  41.   
  42. /* 将文件中数据拷贝到缓冲区,同时文件指针位置偏移,数据大小改变 */  
  43. static int read_packet(voidvoid *opaque, uint8_t *buf, int buf_size)  
  44. {  
  45.     struct buffer_data *bd = (struct buffer_data *)opaque;  
  46.     buf_size = FFMIN(buf_size, bd->size);  
  47.   
  48.     printf("ptr:%p size:%zu ", bd->ptr, bd->size);  
  49.   
  50.     /* copy internal buffer data to buf */  
  51.     memcpy(buf, bd->ptr, buf_size);  
  52.     bd->ptr  += buf_size;  
  53.     bd->size -= buf_size;  
  54.   
  55.     return buf_size;  
  56. }  
  57.   
  58. int main(int argc, charchar *argv[])  
  59. {  
  60.     AVFormatContext *fmt_ctx = NULL;  
  61.     AVIOContext *avio_ctx = NULL;  
  62.     uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;  
  63.     size_t buffer_size, avio_ctx_buffer_size = 4096;  
  64.     charchar *input_filename = NULL;  
  65.     int ret = 0;  
  66.     struct buffer_data bd = { 0 };  
  67.   
  68.     if (argc != 2) {  
  69.         fprintf(stderr, "usage: %s input_file "  
  70.                 "API example program to show how to read from a custom buffer "  
  71.                 "accessed through AVIOContext. ", argv[0]);  
  72.         return 1;  
  73.     }  
  74.     input_filename = argv[1];  
  75.   
  76.     /* register codecs and formats and other lavf/lavc components*/  
  77.     av_register_all();  
  78.   
  79.     /* slurp file content into buffer */  
  80.     /* input_filename : 输入文件的文件名 
  81.      * buffer : 文件开始地址 
  82.      * buffer_size : 文件大小 
  83.      * 类似于UNIX下的mmap函数所实现的功能,返回文件开始指针,文件大小 
  84.      * 经测试,并不耗内存,可视为UNIX下的文件映射 
  85.     */  
  86.     ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);  
  87.     if (ret < 0)  
  88.         goto end;  
  89.   
  90.     /* fill opaque structure used by the AVIOContext read callback */  
  91.     /* bd 是指经过文件映射之后的文件,并不是指需要缓存区 */  
  92.     bd.ptr  = buffer;  
  93.     bd.size = buffer_size;  
  94.   
  95.     /* 初始化文件格式的结构体,就是分配内存 */  
  96.     if (!(fmt_ctx = avformat_alloc_context())) {  
  97.         ret = AVERROR(ENOMEM);  
  98.         goto end;  
  99.     }  
  100.   
  101.     /* 分配内存, 可以自己设置缓冲大小,这里设置的是4K */  
  102.     avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);  
  103.     if (!avio_ctx_buffer) {  
  104.         ret = AVERROR(ENOMEM);  
  105.         goto end;  
  106.     }  
  107.   
  108.     /* avio_ctx_buffer是缓冲区, 
  109.      * avio_ctx_buffer 的初始地址赋值到 avio_ctx->buffer 
  110.      * avio_ctx_buffer_size是缓冲区大小 , 也是每次读取数据的大小 
  111.      * bd 是输入文件文件的映射文件 
  112.      * read_packet 回调函数,读取数据的功能 , 具体在什么情况下才会回调 ? 
  113.      */  
  114.     avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,  
  115.                                   0, &bd, &read_packet, NULL, NULL);  
  116.     if (!avio_ctx) {  
  117.         ret = AVERROR(ENOMEM);  
  118.         goto end;  
  119.     }  
  120.     fmt_ctx->pb = avio_ctx;  
  121.     /* 配置初始化信息 
  122.     * read_packet 回调函数会在这里被调用, 它将输入文件的所有数据都先存入缓存中, 
  123.     * 如果后面有需要用到数据,那么它就从缓存中直接调用数据 
  124.     */  
  125.     ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);  
  126.     if (ret < 0) {  
  127.         fprintf(stderr, "Could not open input ");  
  128.         goto end;  
  129.     }  
  130.   
  131.     ret = avformat_find_stream_info(fmt_ctx, NULL);  
  132.     if (ret < 0) {  
  133.         fprintf(stderr, "Could not find stream information ");  
  134.         goto end;  
  135.     }  
  136.       
  137.     /* 输出基本信息 */  
  138.     av_dump_format(fmt_ctx, 0, input_filename, 0);  
  139.   
  140. end:  
  141.     avformat_close_input(&fmt_ctx);  
  142.     /* note: the internal buffer could have changed, and be != avio_ctx_buffer */  
  143.     //应该就是av_free(&avio_ctx_buffer),但位置不对  
  144.     //两者有差异  
  145.     //printf("%p %p ",avio_ctx_buffer,avio_ctx->buffer);  
  146.     if (avio_ctx) {  
  147.         av_freep(&avio_ctx->buffer);  
  148.         av_freep(&avio_ctx);  
  149.     }  
  150.     av_file_unmap(buffer, buffer_size);  
  151.   
  152.     if (ret < 0) {  
  153.         fprintf(stderr, "Error occurred: %s ", av_err2str(ret));  
  154.         return 1;  
  155.     }  
  156.   
  157.     return 0;  
  158. }  

    这里定义了一个avio_ctx_buffer_size 变量表示每次从文件中读取到少数据到内存。在该例子中,FFMPEG是先把输入的音视频数据全部读取到内存,而并不是需要使用的时候才去读取。

原文地址:https://www.cnblogs.com/lidabo/p/7346345.html