Mode d'entrée de la mémoire AVIO

1.Le rôle d’AVIO

Je pense que le plus important est que vous puissiez personnaliser la lecture et l'écriture, ce qui signifie que vous pouvez utiliser AVIO pour personnaliser le format de l'emballage.

2.Utilisation d'AVIO

/**
 * Allocate and initialize an AVIOContext for buffered I/O. It must be later
 * freed with avio_context_free().
 *
 * @param buffer Memory block for input/output operations via AVIOContext.
 *        The buffer must be allocated with av_malloc() and friends.
 *        It may be freed and replaced with a new buffer by libavformat.
 *        AVIOContext.buffer holds the buffer currently in use,
 *        which must be later freed with av_free().
 * @param buffer_size The buffer size is very important for performance.
 *        For protocols with fixed blocksize it should be set to this blocksize.
 *        For others a typical size is a cache page, e.g. 4kb.
 * @param write_flag Set to 1 if the buffer should be writable, 0 otherwise.
 * @param opaque An opaque pointer to user-specific data.
 * @param read_packet  A function for refilling the buffer, may be NULL.
 *                     For stream protocols, must never return 0 but rather
 *                     a proper AVERROR code.
 * @param write_packet A function for writing the buffer contents, may be NULL.
 *        The function may not change the input buffers content.
 * @param seek A function for seeking to specified byte position, may be NULL.
 *
 * @return Allocated AVIOContext or NULL on failure.
 */
/**
*为缓冲I/O分配和初始化AVIOContext。必须稍后
*释放avio_context_free()。
*
*@参数缓冲区通过AVIOContext进行输入/输出操作的内存块。
*缓冲区必须分配给av_malloc()和朋友。
*它可以被libavformat释放并替换为新的缓冲区。
*AVIOContext.缓冲区保存当前正在使用的缓冲区,
*以后必须用av_free()释放。
*@参数buffer_size缓冲区大小对性能非常重要。
*对于具有固定块大小的协议,应将其设置为此块大小。
*对于其他人,典型大小是缓存页面,例如4kb。
*@参数write_flag如果缓冲区应该是可写的,则设置为1,否则设置为0。
*@参数不透明指向用户特定数据的不透明指针。
*@参数read_packet重新填充缓冲区的函数,可能为NULL。
*对于流协议,绝不能返回0,而是
*正确的AVERROR代码。
*@参数write_packet用于写入缓冲区内容的函数,可能为NULL。
*该功能可能不会改变输入缓冲区的内容。
*@参数查找用于查找指定字节位置的函数,可能为NULL。
*
*@返回分配的AVIOContext或失败时为NULL。
*/

AVIOContext *avio_alloc_context(
                  unsigned char *buffer,
                  int buffer_size,
                  int write_flag,
                  void *opaque,
                  int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
                  int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
                  int64_t (*seek)(void *opaque, int64_t offset, int whence));

Description du paramètre :
 buffer est un tampon créé par l'utilisateur, généralement créé à l'aide de av_malloc.
buffer_size est la taille du tampon.
write_flag : 1 indique que l'AVIO actuel est utilisé pour l'écriture, 0 indique qu'il est utilisé pour la lecture.
opaque : indique les données utilisateur .
read_packet : est une fonction hook pour la lecture. Lorsque Cette fonction est appelée lorsque la lecture est requise.
write_packet : est une fonction hook pour l'écriture. Cette fonction est appelée lorsque l'écriture est requise.
seek : est une fonction hook pour un accès aléatoire. Cette fonction est appelé lorsqu'un accès aléatoire est requis.

Méthode d'utilisation :
créez AVIOContext, puis créez AVFormatContext, liez AVIOContext à AVFormatContext->pb et enfin appelez la fonction avformat_open_input. Cependant, l'URL du deuxième paramètre de la fonction avformat_open_input n'a pas besoin d'être transmise pour le moment. Il suffit de transmettre directement NULL. . .

3.Cas


/**
* @projectName   07-05-decode_audio
* @brief         解码音频,主要的测试格式aac和mp3
* @author        Liao Qingfu
* @date          2020-01-16
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <libavutil/frame.h>
#include <libavutil/mem.h>

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>

#define IO_BUF_SIZE 20480


int read_packet(void *opaque, uint8_t *buf, int buf_size)
{
    
    
    FILE* in_file=opaque;
    int size=fread(buf,1,buf_size,in_file);
    if(size<=0)
    {
    
    
        return AVERROR_EOF;
    }
    return size;
}




static void print_sample_format(const AVFrame *frame)
{
    
    
    printf("ar-samplerate: %uHz\n", frame->sample_rate);
    printf("ac-channel: %u\n", frame->channels);
    printf("f-format: %u\n", frame->format);// 格式需要注意,实际存储到本地文件时已经改成交错模式
}


void decode(AVCodecContext* codec_ctx,AVPacket* packet,AVFrame* frame,FILE* out_file)
{
    
    
     int ret=avcodec_send_packet(codec_ctx,packet);
      if(ret<0)
        {
    
    
          printf("avcodec_send_packet failed: %s\n",av_err2str(ret));
          return ;
      }
      while(ret>=0)
      {
    
    
          ret= avcodec_receive_frame(codec_ctx,frame);
          if(ret<0)
          {
    
    
              break;
          }
          //        /**
          //           P表示Planar(平面),其数据格式排列方式为 :
          //           LLLLLLRRRRRRLLLLLLRRRRRRLLLLLLRRRRRRL...(每个LLLLLLRRRRRR为一个音频帧)
          //           而不带P的数据格式(即交错排列)排列方式为:
          //           LRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRLRL...(每个LR为一个音频样本)
          //        播放范例:   ffplay -ar 48000 -ac 2 -f f32le believe.pcm
          //            并不是每一种都是这样的格式
          //        */
         size_t data_size =  av_get_bytes_per_sample(codec_ctx->sample_fmt);// 每一帧的字节数

         print_sample_format(frame);
         for(int i=0;i<frame->nb_samples;i++)
         {
    
    
             for(int j=0;j<codec_ctx->channels;j++)
             {
    
    
                fwrite(frame->data[j] + data_size *i, 1, data_size, out_file);
                //data[j]的j表示第几个声道,data是一个二维数组,
             }
         }
         printf("2. data_size :%d\n",data_size);
      }

}
int main(int argc,char** argv)
{
    
    
    if(argc!=3)
    {
    
    
        printf("usege:./process <in_file> <out_file>\n");
        return -1;
    }
    char* in_file_name=argv[1];
    char* out_file_name=argv[2];
    FILE* in_file=NULL;
    FILE* out_file=NULL;
    int ret=0;
    //打开文件
    in_file=fopen(in_file_name,"rb");
    if(!in_file)
    {
    
    
        printf("in_file open failed\n");
        return -1;
    }
    out_file=fopen(out_file_name,"wb");
    if(!out_file)
    {
    
    
        printf("out_file open failed\n");
        return -1;
    }

    //自定义IO
    unsigned char * io_buf=(unsigned char *)av_malloc(IO_BUF_SIZE);

    AVIOContext* avio_ctx=avio_alloc_context(io_buf,IO_BUF_SIZE,0,(void*)in_file,read_packet,NULL,NULL);




    //创建复用器上下文
    AVFormatContext* fmt_ctx=avformat_alloc_context();
    if(!fmt_ctx)
    {
    
    
        printf("av_read_frame failed\n");
        return  -1;
    }
    fmt_ctx->pb=avio_ctx;//绑定自定义IO
    ret = avformat_open_input(&fmt_ctx,NULL,NULL,NULL);
    if(ret)
    {
    
    
        printf("avformat_open_input failed:%s \n",av_err2str(ret));
        return -1;
    }
    //创建解码器上下文
    AVCodec* codec=avcodec_find_decoder(AV_CODEC_ID_AAC);
    AVCodecContext* codec_ctx=avcodec_alloc_context3(codec);
    //解码器与解码器上下文绑定
    avcodec_open2(codec_ctx,codec,NULL);



    AVPacket* packet=av_packet_alloc();
    AVFrame * frame=av_frame_alloc();
    while(1)
    {
    
    
        ret=av_read_frame(fmt_ctx,packet);
        if(ret)
        {
    
    
            printf("av_read_frame failed:%s \n",av_err2str(ret));
            break;
        }
        decode(codec_ctx,packet,frame,out_file);
    }

     decode(codec_ctx,NULL,frame,out_file);

    return 0;
}

Je suppose que tu aimes

Origine blog.csdn.net/m0_60565784/article/details/131354508
conseillé
Classement