[FFMPEG-1]最想实现的第一个功能-从mp3中提取pcm数据

我一直觉得从音频中解码出pcm数据是做音频的第一件事,要重要最简单的事情。所以第一个功能实验就是音频转码。

当然了,要我自己写肯定是写不出的,所以就求助于万能的google了。折腾了两天,现在看起来感觉很简单,但是最开始的时候什么都不知道,程序都看不懂,难受的就要不行了。

流程如下(偷来的,嘿嘿)

1,打开音乐文件,调用av_open_input_file()

2,查找audio stream,调用av_find_stream_info()

3,查找对应的decoder,调用avcodec_find_decoder()

4,打开decoder,调用avcodec_open2()

5,读取一桢数据包,调用av_read_frame()

6,解码数据包,调用avcodec_decode_audio4()

7,将解码后的数据返回

没啥说的,上代码。

#include    <stdlib.h>
#include    <stdio.h>
#include    <string.h>
#include    <math.h>

#include    <libavutil/opt.h>
#include    <libavutil/mathematics.h>
#include    <libavutil/imgutils.h>
#include    <libavutil/samplefmt.h>
#include    <libavutil/timestamp.h>
#include    <libavformat/avformat.h>
#include    <libavcodec/avcodec.h>
#include    <libswscale/swscale.h>
#include    <libavutil/mathematics.h>
#include    <libswresample/swresample.h>
#include    <libavutil/channel_layout.h>
#include    <libavutil/common.h>
#include    <libavformat/avio.h>
#include    <libavutil/file.h>

int main(int argc, char * argv[]) {
	const char *input = "ping.mp3";
	const char *outfilename = "test.wav";

	/******************注册解码器************************/
	av_register_all();
	avcodec_register_all();

	/**************初始化并打开AVFormatContext************/
	AVFormatContext *iFormatCtx = NULL;
	iFormatCtx = avformat_alloc_context();
	if (avformat_open_input(&iFormatCtx, input, NULL, NULL) != 0) {
		printf("could not open input_file\n");
		return -1;
	}

	/**************获取文件内音视频流的信息************/
	if (avformat_find_stream_info(iFormatCtx, NULL) < 0) {
		printf("find stream info failed\n");
		return -1;
	}

	/*****************打印format信息*****************/
	av_dump_format(iFormatCtx, 0, input, 0);

	/*****************查找媒体流信息*****************/
	int AudioStreamIndex;
	int i;
	AudioStreamIndex = -1;
	for (i = 0; i < iFormatCtx->nb_streams; i++) {
		if (iFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO
				&& AudioStreamIndex < 0) {
			AudioStreamIndex = i;
			break;
		}
	}
	if (AudioStreamIndex == -1) {
		printf("Cannot find VideoStream\n");
		return -1;
	}

	/*****************初始化并打开解码器ls*****************/
	AVCodecContext *c = NULL;
	AVCodec *iaCodec = NULL;
	c = iFormatCtx->streams[AudioStreamIndex]->codec;
	iaCodec = avcodec_find_decoder(c->codec_id);
	if (iaCodec == NULL) {
		printf("unsupported codec!\n");
		return -1;
	}
	if (iaCodec->capabilities & CODEC_CAP_TRUNCATED)
		c->flags |= CODEC_CAP_TRUNCATED;
	if (avcodec_open2(c, iaCodec, NULL) < 0) {
		printf("could not open the codec\n");
		return -1;
	}

	/*************************************************/
	FILE *outfile = fopen(outfilename, "wb");
	if (!outfile) {
		printf("open outfile failed\n");
		av_free(c);
		return -1;
	}

	/*****************申请一个frame并初始化为默认值******************/
	AVFrame *frame = NULL;
	frame = av_frame_alloc();
	if (!frame) {
		fprintf(stderr, "Could not allocate audio frame\n");
		exit(1);
	}

	/****************初始化存储帧数据的容器AVPacket***************/
	AVPacket ipacket;
	av_init_packet(&ipacket);

	/****************按帧读取数据,直到读完所有帧***************/
	while (av_read_frame(iFormatCtx, &ipacket) >= 0) {
		if (ipacket.stream_index == AudioStreamIndex) {

			while (ipacket.size > 0) {
				int out_size;
				//解码一帧
				int len = avcodec_decode_audio4(c, frame, &out_size, &ipacket);
				if (len < 0) {
					//pktsize = 0;
					printf("Error while decoding\n");
					continue;
				}
				if (out_size) {
					//获取bit_rate
					int data_size = av_get_bytes_per_sample(c->sample_fmt);
					if (data_size < 0) {
						/* This should not occur, checking just for paranoia */
						fprintf(stderr, "Failed to calculate data size\n");
						exit(1);
					}
					//多声道存储
					int i = 0;
					int ch = 0;
					for (i = 0; i < frame->nb_samples; i++) {
						for (ch = 0; ch < c->channels; ch++) {
							fwrite(frame->data[ch] + data_size * i, 1,
									data_size, outfile);
						}
					}
				}
				ipacket.size -= len;
				ipacket.data += len;
			}
		}
	}
	return 0;
}
代码没优化,很多内存泄漏的地方。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值