/**
* 参考于:http://blog.csdn.net/leixiaohua1020/article/details/46890259
*/
#include <stdio.h>
#include <string.h> extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
}; #pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "avutil.lib") // 1 second of 48khz 32bit(4Byte) audio
#define MAX_AUDIO_FRAME_SIZE 192000 int main(int argc, char* argv[])
{
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVPacket packet;
AVFrame *pAudioFrame = NULL;
uint8_t *buffer = NULL;
struct SwrContext *audio_convert_ctx = NULL;
int got_picture;
int audioIndex; char filepath[1024] = "";
printf("Usage: program.exe *.mp3\n");
if (argc == 2)
{
strcpy(filepath, argv[1]);
}
else
{
printf("Could not find a audio file\n");
return -1;
} FILE *fp_pcm = fopen("output.pcm", "wb+");
if (fp_pcm == NULL)
{
printf("FILE open error");
return -1;
} av_register_all(); if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)
{
printf("Couldn't open an input stream.\n");
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
{
printf("Couldn't find stream information.\n");
return -1;
}
audioIndex = -1;
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
audioIndex = i;
break;
}
} if (audioIndex == -1)
{
printf("Couldn't find a audio stream.\n");
return -1;
} pCodecCtx = pFormatCtx->streams[audioIndex]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL)
{
printf("Codec not found.\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
printf("Could not open codec.\n");
return -1;
} pAudioFrame = av_frame_alloc();
if (pAudioFrame == NULL)
{
printf("Could not alloc AVFrame\n");
return -1;
} //音频输出参数
uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;//声道格式
AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;//采样格式
int out_nb_samples = pCodecCtx->frame_size;//nb_samples: AAC-1024 MP3-1152
int out_sample_rate = 44100;//采样率
int out_nb_channels = av_get_channel_layout_nb_channels(out_channel_layout);//根据声道格式返回声道个数
int out_buffer_size = av_samples_get_buffer_size(NULL, out_nb_channels, out_nb_samples, out_sample_fmt, 1); buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE); /**
* 函数声明:struct SwrContext *swr_alloc(void);
* Allocate SwrContext.
*
* If you use this function you will need to set the parameters (manually or
* with swr_alloc_set_opts()) before calling swr_init().
*
* @see swr_alloc_set_opts(), swr_init(), swr_free()
* @return NULL on error, allocated context otherwise
*/ audio_convert_ctx = swr_alloc();
if (audio_convert_ctx == NULL)
{
printf("Could not allocate SwrContext\n");
return -1;
} /**
* 函数声明:struct SwrContext *swr_alloc_set_opts(
* struct SwrContext *s,int64_t out_ch_layout, enum AVSampleFormat out_sample_fmt, int out_sample_rate,
* int64_t in_ch_layout, enum AVSampleFormat in_sample_fmt, int in_sample_rate,
* int log_offset, void *log_ctx);
*
* Allocate SwrContext if needed and set/reset common parameters.
*
* This function does not require s to be allocated with swr_alloc(). On the
* other hand, swr_alloc() can use swr_alloc_set_opts() to set the parameters
* on the allocated context.
*
* @param s existing Swr context if available, or NULL if not
* @param out_ch_layout output channel layout (AV_CH_LAYOUT_*)
* @param out_sample_fmt output sample format (AV_SAMPLE_FMT_*).
* @param out_sample_rate output sample rate (frequency in Hz)
* @param in_ch_layout input channel layout (AV_CH_LAYOUT_*)
* @param in_sample_fmt input sample format (AV_SAMPLE_FMT_*).
* @param in_sample_rate input sample rate (frequency in Hz)
* @param log_offset logging level offset
* @param log_ctx parent logging context, can be NULL
*
* @see swr_init(), swr_free()
* @return NULL on error, allocated context otherwise
*/ /*
int64_t in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);//根据声道数返回默认输入声道格式
swr_alloc_set_opts(audio_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,
in_channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);
*/ swr_alloc_set_opts(audio_convert_ctx, out_channel_layout, out_sample_fmt,out_sample_rate,
pCodecCtx->channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL); /**
* 函数声明:int swr_init(struct SwrContext *s);
* Initialize context after user parameters have been set.
* @note The context must be configured using the AVOption API.
*
* @see av_opt_set_int()
* @see av_opt_set_dict()
*
* @param[in,out] s Swr context to initialize
* @return AVERROR error code in case of failure.
*/
swr_init(audio_convert_ctx); int index = 0;//计数器
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == audioIndex)
{
if (avcodec_decode_audio4(pCodecCtx, pAudioFrame, &got_picture, &packet) < 0)
{
printf("Error in decoding audio frame.\n");
return -1;
}
if (got_picture)
{
/** Convert audio.
* 函数声明:int swr_convert(struct SwrContext *s, uint8_t **out, int out_count,
* const uint8_t **in, int in_count);
* in and in_count can be set to 0 to flush the last few samples out at the
* end.
*
* If more input is provided than output space, then the input will be buffered.
* You can avoid this buffering by using swr_get_out_samples() to retrieve an
* upper bound on the required number of output samples for the given number of
* input samples. Conversion will run directly without copying whenever possible.
*
* @param s allocated Swr context, with parameters set
* @param out output buffers, only the first one need be set in case of packed audio
* @param out_count amount of space available for output in samples per channel
* @param in input buffers, only the first one need to be set in case of packed audio
* @param in_count number of input samples available in one channel
*
* @return number of samples output per channel, negative value on error
*/ swr_convert(audio_convert_ctx, &buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pAudioFrame->data, pAudioFrame->nb_samples);
printf("index:%5d\t pts:%lld\t packet size:%d\n", index, packet.pts, packet.size);
//Write PCM
fwrite(buffer, 1, out_buffer_size, fp_pcm);
index++;
}
}
av_free_packet(&packet);
} fclose(fp_pcm);
swr_free(&audio_convert_ctx);
av_free(buffer);
av_frame_free(&pAudioFrame);
avcodec_close(pCodecCtx);
avformat_close_input(&pFormatCtx); return 0;
}

与解析视频里的YUV/RGB(http://blog.csdn.net/x_iya/article/details/52248929)相同的是,解析出音频的AVFrame同样需要转换。

由于ffmpeg最新版本(从2.1开始貌似)使用avcodec_decode_audio4函数来解码音频,但解码得到的数据类型为float 4bit,而播放器播放的格式一般为S16(signed 16bit),就需要对解码得到的数据进行转换,然而,ffmpeg已经帮我们做好了,只需调用API就可以了,这个函数就是:swr_convert

输出:

使用Audacity打开(注意参数)

问题:

1.有些格式的视频不符合标准,获得的pCodecCtx->frame_size为0

雷老师,我使用wmv格式的视频进行测试,结果不能进行得到正确的pcm文件,文件大小始终为0,发现是out_nb_samples = pCodecCtx->frame_size发生错误,其中pCodecCtx->frame_size为0,导致av_samples_get_buffer_size算出的大小是负数。问过有经验组长,他告诉我有些格式的视频不符合标准,不能从文件头中获取到信息,要在读入一帧后获取,也就是ret = avcodec_decode_audio4( pCodecCtx, pFrame,&got_picture,
packet);之后,从pFrame中获取信息。

发现错误,重新修改程序,就能得到数据了。

2.对于采样率为48000Hz的视频,解析为采样率为44100Hz的pcm时出现杂音,将out_sample_rate设置为

int out_sample_rate = 48000;则没有问题。

FFMPEG学习----分离视音频里的PCM数据的更多相关文章

  1. FFMPEG学习----分离视频里的H.264与YUV数据

    #include <stdio.h> extern "C" { #include "libavcodec/avcodec.h" #include & ...

  2. FFmpeg学习4:音频格式转换

    前段时间,在学习试用FFmpeg播放音频的时候总是有杂音,网上的很多教程是基于之前版本的FFmpeg的,而新的FFmepg3中audio增加了平面(planar)格式,而SDL播放音频是不支持平面格式 ...

  3. 基于FFmpeg的音频编码(PCM数据编码成AAC android)

    概述 在Android上实现录音,并利用 FFmpeg将PCM数据编码成AAC. 详细 代码下载:http://www.demodashi.com/demo/10512.html 之前做的一个demo ...

  4. FFmpeg学习5:多线程播放视音频

    在前面的学习中,视频和音频的播放是分开进行的.这主要是为了学习的方便,经过一段时间的学习,对FFmpeg的也有了一定的了解,本文就介绍了 如何使用多线程同时播放音频和视频(未实现同步),并对前面的学习 ...

  5. 最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)

    ===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...

  6. 最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)

    ===================================================== 最简单的基于FFmpeg的封装格式处理系列文章列表: 最简单的基于FFmpeg的封装格式处理 ...

  7. FFmpeg学习6:视音频同步

    在上一篇文章中,视频和音频是各自独立播放的,并不同步.本文主要描述了如何以音频的播放时长为基准,将视频同步到音频上以实现视音频的同步播放的.主要有以下几个方面的内容 视音频同步的简单介绍 DTS 和 ...

  8. [总结]FFMPEG视音频编解码零基础学习方法--转

    ffmpeg编解码学习   目录(?)[-] ffmpeg程序的使用ffmpegexeffplayexeffprobeexe 1 ffmpegexe 2 ffplayexe 3 ffprobeexe ...

  9. FFMPEG视音频编解码零基础学习方法-b

    感谢大神分享,虽然现在还看不懂,留着大家一起看啦 PS:有不少人不清楚“FFmpeg”应该怎么读.它读作“ef ef em peg” 0. 背景知识 本章主要介绍一下FFMPEG都用在了哪里(在这里仅 ...

随机推荐

  1. 【Python3爬虫】反反爬之解决前端反调试问题

    一.前言 在我们爬取某些网站的时候,会想要打开 DevTools 查看元素或者抓包分析,但按下 F12 的时候,却出现了下面这一幕: 此时网页暂停加载,也就没法运行代码了,直接中断掉了,难道这就能阻止 ...

  2. Linux系统下 docker安装命令

    centos sudo: 使用 root 权限登录 Centos.确保 yum 包更新到最新.yum update 卸载旧版本(如果安装过旧版本的话)yum remove docker docker- ...

  3. 手摸手。完成一个H5 抽奖功能

    要完成一个这样的抽奖功能 构思 奖励物品是通过接口获取的(img) 奖励结果是通过接口获取的(id) 抽奖的动画需要由慢到快再到慢 抽奖转动时间不能太短 抽奖结束需要回调 业务代码和功能代码要分离 先 ...

  4. 「UVA10810」Ultra-QuickSort 解题报告

    题面 看不懂?! 大概的意思就是: 给出一个长度为n的序列,然后每次只能交换相邻的两个数,问最小需要几次使序列严格上升 不断读入n,直到n=0结束 思路: 交换相邻的两个数,这不就类似冒泡排序吗?但是 ...

  5. Hello2020(前四题题解)

    Hello,2020!新的一年从快乐的掉分开始…… 我在m3.codeforces.com这个镜像网站中一开始还打不开D题,我…… 还有话说今天这场为什么那么多二分. 比赛传送门:https://co ...

  6. [技术翻译]使用Nuxt生成静态网站

    本周再来翻译一些技术文章,本次预计翻译三篇文章如下: 04.[译]使用Nuxt生成静态网站(Generate Static Websites with Nuxt) 05.[译]Web网页内容是如何影响 ...

  7. 解决springmvc报错,java.lang.IllegalArgumentException:No converter found for return value of type: class .......

    1.背景 最近在自学java中的三大框架 ssm,在 springmvc 与 mybatis 整合过程中用到 json 数据交互.因为看的视频的是比较早的嘛,一些配置.jar包什么的,要么跟 jdk ...

  8. .Net Core 认证系统之基于Identity Server4 Token的JwtToken认证源码解析

    介绍JwtToken认证之前,必须要掌握.Net Core认证系统的核心原理,如果你还不了解,请参考.Net Core 认证组件源码解析,且必须对jwt有基本的了解,如果不知道,请百度.最重要的是你还 ...

  9. Serverless Kubernetes 入门:对 Kubernetes 做减法

    作者 | 贤维  阿里巴巴高级技术专家 导读:Serverless Kubernetes 是阿里云容器服务团队对未来 Kubernetes 演进方向的一种探索,通过对 Kubernetes 做减法,降 ...

  10. JavaScript 继承小记

    面向对象编程很重要的一个方面,就是对象的继承.A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法.这对于代码的复用是非常有用的. 大部分面向对象的编程语言,都是通过“类”(class) ...