博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ffmpeg 编程常用 pcm 转 aac aac 转 pcm mp4 h264解码
阅读量:4882 次
发布时间:2019-06-11

本文共 5925 字,大约阅读时间需要 19 分钟。

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 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 10 #ifdef __cplusplus 11 extern "C" 12 { 13 #endif 14 #include
15 #include
16 #include
17 #include
18 #include
19 #include
20 #include
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 any178 * 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 播放视频

 

更新中。。

 

转载于:https://www.cnblogs.com/ningci/p/9940645.html

你可能感兴趣的文章
Thinkphp 3.2笔记
查看>>
RHEL7开机不能正常进入系统(图形化界面)
查看>>
Android开发环境搭建完全图解
查看>>
详解BOM头以及去掉BOM头的方法
查看>>
PHP 手机浏览器访问网站获取手机相关信息方法集锦
查看>>
09年电子竞赛参赛技巧经验11条(转载)
查看>>
CSS颜色
查看>>
前端自动化之(一)—浏览器自动实时刷新
查看>>
Unity 摄像头竖屏预览显示的问题
查看>>
HDU 5115 Dire Wolf(区间dp)
查看>>
C# 程序配置文件的操作(ConfigurationManager的使用)
查看>>
Springmvc完成分页的功能
查看>>
JComboBox实现当前所选项功能和JFrame窗口释放资源的dispose()方法
查看>>
tp 引入phpexcel 进行单表格的导入,在线浏览
查看>>
jsp基础速成精华讲解
查看>>
URL to Blob
查看>>
bzoj 3643: Phi的反函数
查看>>
BizTalk Server 2009 Beta初体验
查看>>
HTML中解决双击会选中文本的问题
查看>>
3.单例模式-singleton
查看>>