新版ffmpeg PCM編碼到AAC,swr_convert轉換取樣精度,稍微修改相容PCM編碼為G711A及MP3,記錄下。
阿新 • • 發佈:2018-12-22
#include "stdafx.h" #include <stdio.h> #include <iostream> using namespace std; extern "C" { #include "libavformat/avformat.h" #include "libavutil/avutil.h" #include "libavcodec/avcodec.h" #include "libswresample/swresample.h" #include "libavutil/frame.h" #include "libavutil/samplefmt.h" #include "libavformat/avformat.h" #include "libavcodec/avcodec.h" } #pragma comment(lib, "avcodec.lib") #pragma comment(lib, "avdevice.lib") #pragma comment(lib, "avformat.lib") #pragma comment(lib, "avutil.lib") #pragma comment(lib, "swscale.lib") #pragma comment(lib, "swresample.lib") /* PCM轉AAC */ int main() { /* ADTS頭 */ char *padts = (char *)malloc(sizeof(char) * 7); char *mp3padts = (char *)malloc(sizeof(char) * 4); int profile = 2; //AAC LC int freqIdx = 4; //44.1KHz int chanCfg = 2; //MPEG-4 Audio Channel Configuration. 1 Channel front-center,channel_layout.h padts[0] = (char)0xFF; // 11111111 = syncword padts[1] = (char)0xF1; // 1111 1 00 1 = syncword MPEG-2 Layer CRC padts[2] = (char)(((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2)); padts[6] = (char)0xFC; /*mp3padts[0] = (char)0xFF; mp3padts[1] = (char)0xFB; mp3padts[2] = (char)0x90; mp3padts[3] = (char)0x04;*/ SwrContext *swr_ctx = NULL; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec = NULL; AVFrame *pFrame; AVPacket pkt; AVCodecID codec_id = AV_CODEC_ID_AAC; FILE *fp_in; FILE *fp_out; char filename_in[] = "tdjm.pcm"; char filename_out[] = "audio.G711"; uint8_t **convert_data; //儲存轉換後的資料,再編碼AAC int i, ret, got_output; uint8_t* frame_buf; int size = 0; int y_size; int framecnt = 0; int framenum = 100000; avcodec_register_all(); pCodec = avcodec_find_encoder(codec_id); if (!pCodec) { printf("Codec not found\n"); return -1; } pCodecCtx = avcodec_alloc_context3(pCodec); if (!pCodecCtx) { printf("Could not allocate video codec context\n"); return -1; } pCodecCtx->codec_id = codec_id; pCodecCtx->codec_type = AVMEDIA_TYPE_AUDIO; pCodecCtx->sample_fmt = pCodec->sample_fmts[0]; pCodecCtx->sample_rate = 44100; pCodecCtx->channel_layout = AV_CH_LAYOUT_STEREO; pCodecCtx->channels = av_get_channel_layout_nb_channels(pCodecCtx->channel_layout); //pCodecCtx->frame_size = 1024; if ((ret = avcodec_open2(pCodecCtx, pCodec, NULL)) < 0) { cout << "avcodec_open2 error ----> " << ret; printf("Could not open codec\n"); return -1; } pCodecCtx->frame_size/* = 1024*/; pCodecCtx->bit_rate =128000 ; pFrame = av_frame_alloc(); pFrame->nb_samples = pCodecCtx->frame_size; //1024 pFrame->format = pCodecCtx->sample_fmt; pFrame->channels = 2; /* 由AV_SAMPLE_FMT_S16轉為AV_SAMPLE_FMT_FLTP */ swr_ctx = swr_alloc_set_opts( NULL, av_get_default_channel_layout(pCodecCtx->channels), pCodecCtx->sample_fmt, pCodecCtx->sample_rate, av_get_default_channel_layout(pCodecCtx->channels), AV_SAMPLE_FMT_S16, //PCM原始檔的取樣格式 /*pCodecCtx->sample_rate*/44100, 0, NULL); swr_init(swr_ctx); /* 分配空間 */ convert_data = (uint8_t**)calloc(pCodecCtx->channels, sizeof(*convert_data)); av_samples_alloc(convert_data, NULL, pCodecCtx->channels, pCodecCtx->frame_size, pCodecCtx->sample_fmt, 0); size = av_samples_get_buffer_size(NULL, pCodecCtx->channels, pCodecCtx->frame_size, pCodecCtx->sample_fmt, 0); frame_buf = (uint8_t *)av_malloc(size); /* 此時data[0],data[1]分別指向frame_buf陣列起始、中間地址 */ ret = avcodec_fill_audio_frame(pFrame, pCodecCtx->channels, pCodecCtx->sample_fmt, (const uint8_t*)frame_buf, size, 0); if (ret < 0) { cout << "avcodec_fill_audio_frame error "; return 0; } //Input raw data fp_in = fopen(filename_in, "rb"); if (!fp_in) { printf("Could not open %s\n", filename_in); return -1; } //Output bitstream fp_out = fopen(filename_out, "wb"); if (!fp_out) { printf("Could not open %s\n", filename_out); return -1; } //Encode for (i = 0; i < framenum; i++) { av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; //Read raw data if (fread(frame_buf, 1, 4096, fp_in) <= 0) { printf("Failed to read raw data! \n"); return -1; } else if (feof(fp_in)) { break; } /* 轉換資料,令各自聲道的音訊資料儲存在不同的陣列(分別由不同指標指向)*/ pCodecCtx->sample_fmt; swr_convert(swr_ctx, convert_data, pCodecCtx->frame_size, (const uint8_t**)pFrame->data, pCodecCtx->frame_size); /* 將轉換後的資料複製給pFrame */ int length = pCodecCtx->frame_size * av_get_bytes_per_sample(pCodecCtx->sample_fmt); memcpy(pFrame->data[0], convert_data[0], length); memcpy(pFrame->data[1], convert_data[1], length); pFrame->pts = i*100; ret = avcodec_encode_audio2(pCodecCtx, &pkt, pFrame, &got_output); if (ret < 0) { cout << "error encoding"; return -1; } if (pkt.data == NULL) { av_free_packet(&pkt); continue; } if (got_output) { framecnt++; padts[3] = (char)(((chanCfg & 3) << 6) + ((7 + pkt.size) >> 11)); padts[4] = (char)(((7 + pkt.size) & 0x7FF) >> 3); padts[5] = (char)((((7 + pkt.size) & 7) << 5) + 0x1F); fwrite(padts, 7, 1, fp_out); fwrite(pkt.data, 1, pkt.size, fp_out); av_free_packet(&pkt); } } //Flush Encoder for (got_output = 1; got_output; i++) { ret = avcodec_encode_audio2(pCodecCtx, &pkt, NULL, &got_output); if (ret < 0) { printf("Error encoding frame\n"); return -1; } if (got_output) { padts[3] = (char)(((chanCfg & 3) << 6) + ((7 + pkt.size) >> 11)); padts[4] = (char)(((7 + pkt.size) & 0x7FF) >> 3); padts[5] = (char)((((7 + pkt.size) & 7) << 5) + 0x1F); // fwrite(padts, 7, 1, fp_out); // fwrite(mp3padts, 4, 1, fp_out); fwrite(pkt.data, 1, pkt.size, fp_out); av_free_packet(&pkt); } } fclose(fp_out); avcodec_close(pCodecCtx); av_free(pCodecCtx); av_freep(&pFrame->data[0]); av_frame_free(&pFrame); av_freep(&convert_data[0]); free(convert_data); return 0; }
有兩個疑問,希望知道原理的博友能告知:
1、AV_CODEC_ID_PCM_ALAW這個為G711A編解碼器,編碼器的frame_size為0 ,不知道怎麼回事?需要自己指定,比如和AAC的一樣為1024。
2、轉為MP3、G711A的時候不需要加頭,但是為什麼AAC的需要加頭呢?