忙了幾天終于實(shí)現(xiàn)了轉(zhuǎn)碼,但是只是轉(zhuǎn)碼還是不夠的,還想要進(jìn)行重采樣。同樣的還是要求助于萬能的google,找了一大堆代碼,再加上參考了官方的demo。折騰了兩天,終于搞定了。
大部分的代碼和轉(zhuǎn)碼的代碼差不多,多的地方是需要設(shè)置輸出的格式比如采樣率,聲道,bit_rate等信息。從輸入文件解碼得到數(shù)據(jù)之后要進(jìn)行重采樣的操作,然后保存重采樣之后的數(shù)據(jù)。一開始找了一個講解很詳細(xì)的博客,但是他是用的老版本,很多函數(shù)都廢棄了。后來又想起來官方的example,然后結(jié)合了一下終于搞出來了!因?yàn)槭腔趧e人的代碼修改的,所以代碼風(fēng)格和上一篇不怎么也一樣。
#include <stdlib.h>#include <stdio.h>#include <string.h>#include <math.h>#include <stdint.h>#include <libavutil/avutil.h>#include <libavutil/attributes.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>#include <libswresample/swresample.h>FILE *fin, *fout;#define SWR_CH_MAX 1024int ffmpeg_audio_decode(const char * inFile, const char * outFile, int channel_num, int bit_rate, int sample_rate) { av_register_all(); AVFrame* frame = av_frame_alloc(); if (!frame) { fprintf(stderr, "Error allocating the frame"); return 1; } AVFormatContext* formatContext = NULL; if (avformat_open_input(&formatContext, inFile, NULL, NULL) != 0) { av_free(frame); fprintf(stderr, "Error opening the file"); return 1; } if (avformat_find_stream_info(formatContext, NULL) < 0) { av_free(frame); avformat_close_input(&formatContext); fprintf(stderr, "Error finding the stream info"); return 1; } AVStream* audioStream = NULL; unsigned int i; // Find the audio stream (some container files can have multiple streams in them) for (i = 0; i < formatContext->nb_streams; ++i) { if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { audioStream = formatContext->streams[i]; break; } } if (audioStream == NULL) { av_free(frame); avformat_close_input(&formatContext); fprintf(stderr, "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); avformat_close_input(&formatContext); fprintf(stderr, "Couldn't find a proper decoder"); return 1; } else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0) { av_free(frame); avformat_close_input(&formatContext); fprintf(stderr, "Couldn't open the context with the decoder"); return 1; } /*START*************************START***********************START*/ /*設(shè)置輸出格式,為了未來jni調(diào)用的簡單,所以都傳的int,反正是自己用的,直觀一些*/ int64_t outChannelLayout; if (channel_num == 1) { outChannelLayout = AV_CH_LAYOUT_MONO; } else { outChannelLayout = AV_CH_LAYOUT_STEREO; } enum AVSampleFormat outSampleFormat; if (bit_rate == 32) { outSampleFormat = AV_SAMPLE_FMT_S32; } else { outSampleFormat = AV_SAMPLE_FMT_S16; } int outSampleRate = sample_rate; //44100; SwrContext* swrContext = swr_alloc_set_opts(NULL, outChannelLayout, outSampleFormat, outSampleRate, av_get_default_channel_layout(codecContext->channels), codecContext->sample_fmt, codecContext->sample_rate, 0, NULL); if (swrContext == NULL) { av_free(frame); avcodec_close(codecContext); avformat_close_input(&formatContext); fprintf(stderr, "Couldn't create the SwrContext"); return 1; } if (swr_init(swrContext) != 0) { av_free(frame); avcodec_close(codecContext); avformat_close_input(&formatContext); swr_free(&swrContext); fprintf(stderr, "Couldn't initialize the SwrContext"); return 1; } /*END**************************END*************************END*/ fout = fopen(outFile, "wb+"); AVPacket packet; av_init_packet(&packet);// Read the packets in a loop while (av_read_frame(formatContext, &packet) == 0) { if (packet.stream_index == audioStream->index) { AVPacket decodingPacket = packet; while (decodingPacket.size > 0) { // Try to decode the packet into a frame int frameFinished = 0; int result = avcodec_decode_audio4(codecContext, frame, &frameFinished, &decodingPacket); if (result < 0 || frameFinished == 0) { break; } unsigned char buffer[100000]; unsigned char* pointers[SWR_CH_MAX]; pointers[0] = &buffer[0]; //這個地方還不是很清楚,看官方的example感覺好復(fù)雜。尤其是參數(shù)。 int numSamplesOut = swr_convert(swrContext, pointers, outSampleRate, (const unsigned char**) frame->extended_data, frame->nb_samples); fwrite((short *) buffer, sizeof(short), (size_t) numSamplesOut * channel_num, fout); decodingPacket.size -= result; decodingPacket.data += result; } } av_free_packet(&packet); } // Clean up! av_free(frame); avcodec_close(codecContext); avformat_close_input(&formatContext); fclose(fout); return 0;}int main() { char *inFile = "ping.mp3"; char *outFile = "ping.wav"; fprintf(stderr, "res:%d/n", ffmpeg_audio_decode(inFile, outFile, 2, 16, 44100)); return 0;}
代碼未經(jīng)充分測試,總感覺又一些問題。忘了加頭了,現(xiàn)在把頭加上。感覺自己寫的程序越來越不靠譜了!但是基本呢功能還是能實(shí)現(xiàn)的。
#include <stdlib.h>#include <stdio.h>#include <string.h>#include <math.h>#include <stdint.h>#include <libavutil/avutil.h>#include <libavutil/attributes.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>#include <libswresample/swresample.h>FILE *fin, *fout;#define SWR_CH_MAX 1024typedef struct { unsigned long samplerate; unsigned int bits_per_sample; unsigned int channels; unsigned long total_samples;} WavHeader;int write_wav_header(unsigned char header[], WavHeader *wavHeader) { //unsigned char header[44]; unsigned char* p = header; unsigned int bytes = (wavHeader->bits_per_sample + 7) / 8; float data_size = (float) bytes * wavHeader->total_samples; unsigned long word32; *p++ = 'R'; *p++ = 'I'; *p++ = 'F'; *p++ = 'F'; //RIFF 4 word32 = (unsigned long) data_size + (44 - 8); *p++ = (unsigned char) (word32 >> 0); *p++ = (unsigned char) (word32 >> 8); *p++ = (unsigned char) (word32 >> 16); *p++ = (unsigned char) (word32 >> 24); //數(shù)據(jù)長度 4+4 *p++ = 'W'; *p++ = 'A'; *p++ = 'V'; *p++ = 'E'; //WAVE 4+4+4 *p++ = 'f'; *p++ = 'm'; *p++ = 't'; *p++ = ' '; //fmt 4+4+4+4 *p++ = 0x10; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00; //16 4+4+4+4+4=20 *p++ = 0x01; *p++ = 0x00; //1 4+4+4+4+4+2=22 *p++ = (unsigned char) (wavHeader->channels >> 0); *p++ = (unsigned char) (wavHeader->channels >> 8); //聲道數(shù) 4+4+4+4+4+2+2=24 word32 = (unsigned long) (wavHeader->samplerate + 0.5); *p++ = (unsigned char) (word32 >> 0); *p++ = (unsigned char) (word32 >> 8); *p++ = (unsigned char) (word32 >> 16); *p++ = (unsigned char) (word32 >> 24); //采樣率 4+4+4+4+4+2+2+4=28 word32 = wavHeader->samplerate * bytes * wavHeader->channels; *p++ = (unsigned char) (word32 >> 0); *p++ = (unsigned char) (word32 >> 8); *p++ = (unsigned char) (word32 >> 16); *p++ = (unsigned char) (word32 >> 24); //每秒所需字節(jié)數(shù) 4+4+4+4+4+2+2+4=32 word32 = bytes * wavHeader->channels; *p++ = (unsigned char) (word32 >> 0); *p++ = (unsigned char) (word32 >> 8); // blockAlign(2個字節(jié)) 4+4+4+4+4+2+2+4+2=34 //每個采樣需要的字節(jié)數(shù),計(jì)算公式:聲道數(shù) * 每個采樣需要的bit / 8 *p++ = (unsigned char) (wavHeader->bits_per_sample >> 0); *p++ = (unsigned char) (wavHeader->bits_per_sample >> 8); //bitPerSample(2個字節(jié))4+4+4+4+4+2+2+4+2+2=36 //每個采樣需要的bit數(shù),一般為8或16 *p++ = 'd'; *p++ = 'a'; *p++ = 't'; *p++ = 'a'; //data 4+4+4+4+4+2+2+4+2+2+4=40 word32 = (unsigned long) data_size; *p++ = (unsigned char) (word32 >> 0); *p++ = (unsigned char) (word32 >> 8); *p++ = (unsigned char) (word32 >> 16); *p++ = (unsigned char) (word32 >> 24); //size2(4個字節(jié)) 4+4+4+4+4+2+2+4+2+2+4+4=44 // 錄音數(shù)據(jù)的長度,不包括頭部長度 return 0;}int ffmpeg_audio_decode(const char * inFile, const char * outFile, int channel_num, int bit_rate, int sample_rate) { av_register_all(); AVFrame* frame = av_frame_alloc(); if (!frame) { fprintf(stderr, "Error allocating the frame"); return 1; } AVFormatContext* formatContext = NULL; if (avformat_open_input(&formatContext, inFile, NULL, NULL) != 0) { av_free(frame); fprintf(stderr, "Error opening the file"); return 1; } if (avformat_find_stream_info(formatContext, NULL) < 0) { av_free(frame); avformat_close_input(&formatContext); fprintf(stderr, "Error finding the stream info"); return 1; } AVStream* audioStream = NULL; unsigned int i; // Find the audio stream (some container files can have multiple streams in them) for (i = 0; i < formatContext->nb_streams; ++i) { if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { audioStream = formatContext->streams[i]; break; } } if (audioStream == NULL) { av_free(frame); avformat_close_input(&formatContext); fprintf(stderr, "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); avformat_close_input(&formatContext); fprintf(stderr, "Couldn't find a proper decoder"); return 1; } else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0) { av_free(frame); avformat_close_input(&formatContext); fprintf(stderr, "Couldn't open the context with the decoder"); return 1; } /*START*************************START***********************START*/ /*設(shè)置輸出格式,為了未來jni調(diào)用的簡單,所以都傳的int,反正是自己用的,直觀一些*/ int64_t outChannelLayout; if (channel_num == 1) { outChannelLayout = AV_CH_LAYOUT_MONO; } else { outChannelLayout = AV_CH_LAYOUT_STEREO; } enum AVSampleFormat outSampleFormat; if (bit_rate == 32) { outSampleFormat = AV_SAMPLE_FMT_S32; } else { outSampleFormat = AV_SAMPLE_FMT_S16; } int outSampleRate = sample_rate; //44100; SwrContext* swrContext = swr_alloc_set_opts(NULL, outChannelLayout, outSampleFormat, outSampleRate, av_get_default_channel_layout(codecContext->channels), codecContext->sample_fmt, codecContext->sample_rate, 0, NULL); if (swrContext == NULL) { av_free(frame); avcodec_close(codecContext); avformat_close_input(&formatContext); fprintf(stderr, "Couldn't create the SwrContext"); return 1; } if (swr_init(swrContext) != 0) { av_free(frame); avcodec_close(codecContext); avformat_close_input(&formatContext); swr_free(&swrContext); fprintf(stderr, "Couldn't initialize the SwrContext"); return 1; } /*END**************************END*************************END*/ fout = fopen(outFile, "wb+"); AVPacket packet; av_init_packet(&packet); double duration = (double) formatContext->duration / 1000.0 / 1000.0; fprintf(stderr, "duration=%f/n", duration); int total_sample = (int) duration * channel_num * sample_rate; fprintf(stderr, "total_sample=%d/n", total_sample); int count = 0; fseek(fout,44, SEEK_SET); while (av_read_frame(formatContext, &packet) == 0) { if (packet.stream_index == audioStream->index) { AVPacket decodingPacket = packet; while (decodingPacket.size > 0) { // Try to decode the packet into a frame int frameFinished = 0; int result = avcodec_decode_audio4(codecContext, frame, &frameFinished, &decodingPacket); if (result < 0 || frameFinished == 0) { break; } unsigned char buffer[100000]; unsigned char* pointers[SWR_CH_MAX]; pointers[0] = &buffer[0]; //這個地方還不是很清楚,看官方的example感覺好復(fù)雜。尤其是參數(shù)。 int numSamplesOut = swr_convert(swrContext, pointers, outSampleRate, (const unsigned char**) frame->extended_data, frame->nb_samples); fwrite((short *) buffer, sizeof(short), (size_t) numSamplesOut * channel_num, fout); count += numSamplesOut* channel_num; decodingPacket.size -= result; decodingPacket.data += result; } } av_free_packet(&packet); } fprintf(stderr, "count=%d/n", count); unsigned char header[44]; WavHeader h; h.bits_per_sample = bit_rate; h.channels = channel_num; h.samplerate = sample_rate; h.total_samples = count; write_wav_header(header, &h); fseek(fout,0, SEEK_SET); fwrite(&header, 1, 44, fout); // Clean up! av_free(frame); avcodec_close(codecContext); avformat_close_input(&formatContext); fclose(fout); return 0;}int main() { char *inFile = "ping.mp3"; char *outFile = "ping.wav"; fprintf(stderr, "res:%d/n", ffmpeg_audio_decode(inFile, outFile, 2, 16, 44100)); return 0;}