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

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

经常使用的功能有:c++

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

ffmpeg 的使用都差很少,查找解码器,准备数据,解码,拿结果。网络

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

介绍几个很是实用的例子:网站

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

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

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

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

现实的需求中,没有人让你作一个格式转换器。多是从 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\n\r", 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 \n"); 117         return -1; 118  } 119 
120     codecContext = avcodec_alloc_context3(codec); 121     if(! codecContext) 122  { 123         printf("Could not allocate audio codec context \n"); 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 \n", 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 \n"); 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 \n"); 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 \n", 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 \n"); 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 \n"); 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 播放视频

 

更新中。。

相关文章
相关标签/搜索