• ffmpeg 编程常用 pcm 转 aac aac 转 pcm mp4 h264解码


    ffmpeg 是现在开源的全能编解码器,基本上全格式都支持,纯 c 语言作成,相对比其它的 VLC ,GStreamer glib2 写的,开发更简单些,文档很棒,就是 examples 比较少。

    常用的功能有:

    AVFrame 数据帧
    AVCodecContext 编解码器
    AVPacket 数据帧
    swr_convert 格式转换器

    ffmpeg 的使用都差不多,查找解码器,准备数据,解码,拿结果。

    基本上会了一种,其它的也就能会,新版的 4.x 的代码较之前的有些变化,现在大部分之前的代码也是兼容的。有一些 定义成了 enum 。

    介绍几个非常实用的例子:

    1, pcm 编码 aac (aac 和 m4a 是一种类型)

    需要 libfdk_aac 库自行安装配置好,使用 ubuntu 16.0.4 x64 g++ 编译

    g++ -g main.cpp -lavcodec -lavformat -lswresample -lavutil -std=c++11 -o wav_to_m4a

    用法 ./wav_to_m4a ../xxx.wav ,需要说明的是,有些网站下载的 wav 根本不能用,最好是用 ffmpeg 命令转换。

    现实的需求中,没有人让你做一个格式转换器。可能是从 ALSA 读取原始PCM 在编码成 AAC 或通过网络发走,或保存文件。

    下面的例子,仅是编码成了 AAC 但是未添加 AAC 头信息。有空在更新。但是可以用 播放器放的。

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <iostream>
      4 #include <fstream>
      5 #include <sys/types.h>
      6 #include <sys/stat.h>
      7 #include <fcntl.h>
      8 #include <sys/mman.h>
      9 
     10 #ifdef __cplusplus
     11 extern "C" 
     12 {
     13 #endif
     14 #include <libavformat/avformat.h>
     15 #include <libavcodec/avcodec.h>
     16 #include <libavutil/channel_layout.h>
     17 #include <libavutil/common.h>
     18 #include <libavutil/frame.h>
     19 #include <libavutil/samplefmt.h>
     20 #include <libavutil/mem.h>
     21 #ifdef __cplusplus
     22 }
     23 #endif
     24 
     25 #ifndef WORD
     26 #define WORD unsigned short
     27 #endif
     28 
     29 #ifndef DWORD
     30 #define DWORD unsigned int
     31 #endif
     32     
     33 struct RIFF_HEADER
     34 {
     35     char szRiffID[4];  // 'R','I','F','F'
     36     DWORD dwRiffSize;
     37     char szRiffFormat[4]; // 'W','A','V','E'
     38 };
     39 
     40 struct WAVE_FORMAT
     41 {
     42     WORD wFormatTag;
     43     WORD wChannels;
     44     DWORD dwSamplesPerSec;
     45     DWORD dwAvgBytesPerSec;
     46     WORD wBlockAlign;
     47     WORD wBitsPerSample;
     48 };
     49 
     50 struct FMT_BLOCK
     51 {
     52     char  szFmtID[4]; // 'f','m','t',' '
     53     DWORD  dwFmtSize;
     54     struct WAVE_FORMAT wavFormat;
     55 };
     56 
     57 struct DATA_BLOCK
     58 {
     59     char szDataID[4]; // 'd','a','t','a'
     60     DWORD dwDataSize;
     61 };
     62 
     63 using namespace std;
     64 
     65 void read_wav(uint8_t *wav_buf, int *fs, int *channels, int *bits_per_sample, int *wav_size, int *file_size)
     66 {
     67     struct RIFF_HEADER *headblk;
     68     struct FMT_BLOCK   *fmtblk;
     69     struct DATA_BLOCK  *datblk;
     70 
     71     headblk = (struct RIFF_HEADER *) wav_buf;
     72     fmtblk  = (struct FMT_BLOCK *) &headblk[1];
     73     datblk  = (struct DATA_BLOCK *) &fmtblk[1];
     74     
     75     *file_size = headblk->dwRiffSize;
     76 
     77     //采样频率
     78     *fs        = fmtblk->wavFormat.dwSamplesPerSec;
     79     //通道数
     80     *channels  = fmtblk->wavFormat.wChannels;
     81     *wav_size  = datblk->dwDataSize;
     82     //采样bit数 16 24
     83     *bits_per_sample = fmtblk->wavFormat.wBitsPerSample;
     84 }
     85 
     86 int main(int argc, char **argv)
     87 {
     88     int fd;
     89     int ret;
     90     struct stat stat;
     91     int fs, channels, bits_per_sample, wav_size, file_size;
     92     uint8_t *wav_buf;
     93     uint8_t *audio_buf;    
     94     const char           *out_file = "out.m4a";
     95     const AVCodec        *codec;
     96     AVFrame              *frame;
     97     AVPacket             *encodePacket;
     98     AVCodecContext       *codecContext;
     99     
    100     //打开文件进行 mmap 
    101     fd = open(argv[1], O_RDONLY);
    102     fstat(fd, &stat);
    103     wav_buf = (uint8_t*)mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
    104     read_wav(wav_buf, &fs, &channels, &bits_per_sample, &wav_size, &file_size);
    105     printf("wav format: fs = %d, channels = %d, bits_per_sample = %d, wav_size = %d file_size = %d
    
    ", fs, channels, bits_per_sample, wav_size, file_size);
    106     
    107     //真实wav 跳过头部
    108     audio_buf = wav_buf + sizeof(struct RIFF_HEADER) + sizeof(struct FMT_BLOCK) + sizeof(struct DATA_BLOCK);
    109 
    110     avcodec_register_all(); //ffmpeg 4.x 已经不需要此函数
    111     
    112     codec =  avcodec_find_encoder_by_name("libfdk_aac");
    113 
    114     if(! codec)
    115     {
    116         printf("avcodec_find_encoder error 
    ");
    117         return -1;
    118     }
    119 
    120     codecContext = avcodec_alloc_context3(codec);
    121     if(! codecContext)
    122     {
    123         printf("Could not allocate audio codec context 
    ");
    124         return -1;
    125     }
    126 
    127     codecContext->bit_rate       = 64000;
    128     codecContext->sample_fmt     = AV_SAMPLE_FMT_S16; 
    129     codecContext->sample_rate    = 44100;
    130     codecContext->channel_layout = AV_CH_LAYOUT_STEREO;
    131     codecContext->channels       = av_get_channel_layout_nb_channels(codecContext->channel_layout);
    132 
    133     printf("sample_fmt:%d sample_rate:%d channel_layout:%d channels:%d 
    ", codecContext->sample_fmt, codecContext->sample_rate, codecContext->channel_layout, codecContext->channels);
    134 
    135     /* open avcodec */
    136     if(0 > avcodec_open2(codecContext, codec, NULL))
    137     {
    138         printf("Could not open codec 
    ");
    139         return -1;
    140     }
    141 
    142     /* frame containing input raw audio */
    143     frame = av_frame_alloc();
    144     if(! frame)
    145     {
    146         printf("Could not allocate audio frame 
    ");
    147         return -1;
    148     }
    149 
    150     frame->nb_samples     = codecContext->frame_size;
    151     frame->format         = codecContext->sample_fmt;
    152     frame->channel_layout = codecContext->channel_layout;
    153 
    154     printf("nb_samples:%d format:%d channel_layout:%d 
    ", frame->nb_samples, frame->format, frame->channel_layout);
    155 
    156     encodePacket = av_packet_alloc();
    157     
    158     int size = av_samples_get_buffer_size(NULL, codecContext->channels,codecContext->frame_size,codecContext->sample_fmt, 1);
    159     uint8_t *frame_buf = (uint8_t *)av_malloc(size);
    160     avcodec_fill_audio_frame(frame, codecContext->channels, codecContext->sample_fmt,(const uint8_t*)frame_buf, size, 1);
    161     
    162     ofstream acc_file(out_file, ios::binary | ios::out | ios::trunc);
    163 
    164     int pos = 0;
    165     while(pos <= file_size)
    166     {
    167         frame->data[0] = audio_buf + pos;
    168 
    169         /* send the frame for encoding */
    170         ret = avcodec_send_frame(codecContext, frame);
    171         if(0 > ret)
    172         {
    173             printf("Error sending the frame to the encoder 
    ");
    174             return -1;
    175         }
    176 
    177         /* read all the available output packets (in general there may be any
    178          * number of them */
    179         while(0 <= ret)
    180         {
    181             ret = avcodec_receive_packet(codecContext, encodePacket);
    182             if(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
    183                 break;
    184             else if(0 > ret)
    185             {
    186                 printf("Error encoding audio frame 
    ");
    187                 return -1;
    188             }
    189 
    190             //c++ 写文件流
    191             acc_file.write((const char*)encodePacket->data, encodePacket->size);
    192             av_packet_unref(encodePacket);
    193         }
    194 
    195         pos += size;
    196     }
    197 
    198     cout << "encode done" << endl;
    199     return 0;
    200 }
    201 
    202 // main.cpp

    2, acc 解码 pcm

    3, mp4 解码 h264 acc 并调用 SDL 播放视频

    更新中。。

  • 相关阅读:
    WINDOWS SERVER 2008 RD服务器搭建
    EXCEL技巧——SUBTOTAL函数巧妙应用
    快速理解几种常用的RAID磁盘阵列级别
    有道云笔记去除左下角广告
    git教程
    .Net导出pdf文件,C#实现pdf导出
    时间控件只显示年月
    C#中日期和时间相加的方法
    JS获取当前时间
    六大设计原则
  • 原文地址:https://www.cnblogs.com/ningci/p/9940645.html
Copyright © 2020-2023  润新知