ffmpeg解复用解码重采样

来源:互联网 发布:垂帘听政知乎 编辑:程序博客网 时间:2024/06/06 06:42
        之前有个片源输出有吵杂的声音,然后为了和板子输出的音频比较,我就在linux PC上参照一下我们的工程和网上的一些方法,写了这么一个程序。
要开始播放是一个视频,到音频的输出,大概经历了这个几个过程:解复用(抽取视音频流)->解码音频->重采样。最终从重采样出来的数据,是可以从音频驱动直接输出的。

        重采样的话,应该不是必须的,然而我们项目是用安卓的架构,HAL层有了输出参数的设定(采样率48K,双声道,采样格式AV_SAMPLE_FMT_S16)。

  下面是代码,写得很烂,初始化和反初始化乱七八糟的,我也不想改了,反正是我自己用的demo而已,贴上来之前,我去掉了很多东西,不一定能编译过,反正是这个逻辑了。几个月前写的东西,都几乎忘光。

#include "libavformat/avformat.h"#include "libavcodec/avcodec.h"#include "libavutil/avutil.h"#include <libswscale/swscale.h>#include <libswresample/swresample.h>#include "stdio.h"#include "math.h"#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audioint main(int argc ,char **argv){if (argc !=2){printf("useage:%s INPUTFILE\n", argv[0]);return -1;}char *outdec="dec.pcm";int fd_out = open(outdec, O_WRONLY, 0666);if (fd_out < 0){printf("open in file is failed\n");return -1;}av_register_all();AVFrame* frame = avcodec_alloc_frame();if (!frame){printf( "Error allocating the frame" );return -1;}AVFormatContext* formatContext = NULL;if (avformat_open_input(&formatContext, argv[1], NULL, NULL) != 0){av_free(frame);printf( "Error opening the file" );return -1;}if (avformat_find_stream_info(formatContext, NULL) < 0){av_free(frame);//av_close_input_file(formatContext);printf( "Error finding the stream info" );return -1;}AVStream* audioStream = NULL;unsigned int i = 0;for (; i < formatContext->nb_streams; ++i){if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)//查找音频流对应的ID{audioStream = formatContext->streams[i];break;}}if (audioStream == NULL){av_free(frame);////av_close_input_file(formatContext);printf( "Could not find any audio stream in the file" );return 1;}AVCodecContext* codecContext = audioStream->codec;codecContext->codec = avcodec_find_decoder(codecContext->codec_id);if (codecContext->codec == NULL){av_free(frame);////av_close_input_file(formatContext);printf( "Couldn't find a proper decoder" );return -1;}else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0){av_free(frame);////av_close_input_file(formatContext);printf( "Couldn't open the context with the decoder" );return 1;}/* 重采样格式初始化 */SwrContext* swrContext = NULL;printf(" bit_rate = %d \r\n", codecContext->bit_rate);printf(" sample_rate = %d \r\n", codecContext->sample_rate);printf(" channels = %d \r\n", codecContext->channels);printf(" channel_layout = %d \r\n", codecContext->channel_layout);printf(" code_name = %s \r\n", codecContext->codec->name);printf(" av_get_default_channel_layout(2) %d \r\n", av_get_default_channel_layout(2));swrContext = swr_alloc_set_opts(NULL,av_get_default_channel_layout(2), // out channel layoutAV_SAMPLE_FMT_S16, // out sample format48000, // out sample ratecodecContext->channel_layout, // in channel layoutcodecContext->sample_fmt, // in sample formatcodecContext->sample_rate, // in sample rate0, // log offsetNULL); // log contextif(swr_init(swrContext)<0){printf("swr_init() for AV_SAMPLE_FMT_S16 fail");swr_free(&swrContext);av_free(frame);////av_close_input_file(formatContext);return -1;}if (!swrContext){swr_free(&swrContext);av_free(frame);avcodec_close(codecContext);////av_close_input_file(formatContext);swrContext = NULL;printf( "Couldn't allocate and set the resampling context" );return -1;}//int bufSize = av_samples_get_buffer_size(NULL, codecContext->channels, codecContext->sample_rate, codecContext->sample_fmt, 0);//unsigned char* buf = new unsigned char[bufSize];AVPacket *packet=(AVPacket *)av_mallocz(sizeof(AVPacket));av_init_packet(packet);static unsigned char audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2]; unsigned char *out[]={audio_buf};  unsigned char *pktdata;int pktsize,flush_complete=0;int resampled_data_size = 0;while (av_read_frame(formatContext, packet) == 0){if (packet->stream_index == audioStream->index) //只处理音频{int got_frame = 0;int len = 0;while (packet->size > 0){len = avcodec_decode_audio4(codecContext, frame, &got_frame, packet); //音频解码if (len < 0){av_free_packet(packet);swr_free(&swrContext);av_free(frame);avcodec_close(codecContext);////av_close_input_file(formatContext);swrContext = NULL;printf( " audio decode error ! \n" );return -1;}packet->data += len; //必须考虑一包解多次的情况packet->size -= len;if (got_frame)//获取一帧的音频{//const unsigned char **in = (const unsigned char **) src_pp;const unsigned char **in = (const unsigned char **) frame->extended_data;int len2 = swr_convert(swrContext, out,sizeof(audio_buf)/codecContext->channels/av_get_bytes_per_sample(AV_SAMPLE_FMT_S16),in, frame->nb_samples);if (len2 < 0) {fprintf(stderr, "audio_resample() failed\n");av_free_packet(packet);swr_free(&swrContext);av_free(frame);avcodec_close(codecContext);////av_close_input_file(formatContext);swrContext = NULL;printf( " audio decode error ! \n" );return -1;}if (len2 == sizeof(audio_buf) / codecContext->channels / av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)) {fprintf(stderr, "warning: audio buffer is probably too small\n");swr_init(swrContext);}resampled_data_size = len2 * (2) * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);write(fd_out, *out, resampled_data_size);}}}av_init_packet(packet);}end:av_free_packet(packet);//delete [] buf;swr_free(&swrContext);av_free(frame);avcodec_close(codecContext);//av_close_input_file(formatContext);close(fd);}


0 0