ffmpeg 提取pcm 儲存為wav
阿新 • • 發佈:2018-12-17
#include "stdafx.h" #ifdef __cplusplus extern "C" { #endif #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavdevice/avdevice.h" #include "libavfilter/avfilter.h" #include "libavfilter/avfiltergraph.h" #include "libavfilter/buffersink.h" #include "libavfilter/buffersrc.h" #include "libavutil/audio_fifo.h" #include "libavutil/avutil.h" #include "libavutil/fifo.h" #include "libswresample/swresample.h" #ifdef __cplusplus } #endif #include <windows.h> #include <conio.h> #include <time.h> #include <tchar.h> #include <stdio.h> #include <cstring> void writeWavHeader(AVCodecContext *pCodecCtx, AVFormatContext *pFormatCtx, FILE *audioFile); int openinputfile(const char* filename) ; #define MAX_AUDIO_FRAME_SIZE 192000 uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;//聲道格式 AVSampleFormat out_sample_fmt =AV_SAMPLE_FMT_S16;//取樣格式 AVFormatContext *ifmt_ctx = NULL; int AudioStreamIndex = -1; int got_frame ,ret = -1; //char *filename = "E:\\摩登兄弟劉宇寧 - 有多少愛可以重來.mp3"; //char *filename="E:\\1.mp3"; //char *filename="E:\\音訊.mp3"; //char *filename="E:\\1.mp4"; //char * filename="E:\\sample.mp4"; char * filename="E:\\Nocturne.m4a"; int main() { AVCodecContext *pCodecCtx; int channels=0; int sample_rate=0; AVPacket pkt_in, pkt_out; AVFrame *frame = NULL; uint8_t *buffer = NULL; struct SwrContext *audio_convert_ctx = NULL; char* extention; av_register_all(); if (openinputfile(filename) < 0) { printf("failed to open input file"); goto end; } extention = strrchr(filename , '.') + 1; int isSame= strcmp(extention,"wav"); FILE *p = NULL; char tmpName[100]; sprintf_s(tmpName, "%s_%d_%dchannel.wav", filename, ifmt_ctx->streams[AudioStreamIndex]->codec->sample_rate, ifmt_ctx->streams[AudioStreamIndex]->codec->channels); p = fopen(tmpName, "w+b"); int size = av_get_bytes_per_sample(ifmt_ctx->streams[AudioStreamIndex]->codec->sample_fmt); av_dump_format(ifmt_ctx, 0, filename, 0); if(AudioStreamIndex>=0) { pCodecCtx=ifmt_ctx->streams[AudioStreamIndex]->codec; printf("聲道數:%d\n",pCodecCtx->channels); printf("時長:%d\n", ifmt_ctx->duration / 1000); channels=pCodecCtx->channels; sample_rate=pCodecCtx->sample_rate; writeWavHeader(pCodecCtx,ifmt_ctx,p); } //音訊輸出引數 int out_nb_samples = pCodecCtx->frame_size;//nb_samples: AAC-1024 MP3-1152 int out_sample_rate =pCodecCtx->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); audio_convert_ctx = swr_alloc(); if (audio_convert_ctx == NULL) { printf("Could not allocate SwrContext\n"); return -1; } 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); swr_init(audio_convert_ctx); int frameindex=0; while(1) { if (av_read_frame(ifmt_ctx, &pkt_in) < 0) { break; } av_init_packet(&pkt_out); if (AudioStreamIndex == pkt_in.stream_index) { frame = av_frame_alloc(); ret = avcodec_decode_audio4(ifmt_ctx->streams[AudioStreamIndex]->codec, frame, &got_frame, &pkt_in); if (ret < 0) { av_frame_free(&frame); printf("decoding audio stream failed\n"); break; } if (got_frame) { frameindex++; if(isSame) { swr_convert(audio_convert_ctx, &buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)frame->data, frame->nb_samples<1000?1152:frame->nb_samples); printf("index:%5d\t pts:%lld\t packet size:%d\n", frameindex, pkt_in.pts, pkt_in.size); fwrite(buffer, 1, out_buffer_size, p); } else { if(frame->data[0]) { fwrite(frame->data[0], 1, frame->linesize[0], p); } } } } } printf("總幀數:%d\n",frameindex); fclose(p); end: swr_free(&audio_convert_ctx); av_free(buffer); avcodec_close(pCodecCtx); avformat_close_input(&ifmt_ctx); printf("enter any key to stop\n"); //getchar(); return 0; } int openinputfile(const char* filename) { //open the input if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) { printf("can not open input"); return ret; } if ((ret = avformat_find_stream_info(ifmt_ctx, NULL))) { printf("can not find input stream info"); return ret; } //open the decoder for (int i = 0; i <(int)ifmt_ctx->nb_streams; i++) { if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { AudioStreamIndex = i; ret = avcodec_open2(ifmt_ctx->streams[i]->codec,avcodec_find_decoder(ifmt_ctx->streams[i]->codec->codec_id), NULL); if (ret < 0) { printf("can not open decoder"); return ret; } } } return 0; } void writeWavHeader(AVCodecContext *pCodecCtx, AVFormatContext *pFormatCtx, FILE *audioFile) { //wav檔案有44位元組的wav頭,所以要寫44位元組的wav頭 int8_t *data; UINT32 long_temp; UINT16 short_temp; UINT16 BlockAlign; int bits = 8; UINT64 fileSize; UINT64 audioDataSize; switch (pCodecCtx->sample_fmt) { case AV_SAMPLE_FMT_S16: bits = 16; break; case AV_SAMPLE_FMT_S32: bits = 32; break; case AV_SAMPLE_FMT_U8: bits = 8; break; default: bits = 16; break; } audioDataSize = (pFormatCtx->duration)*(bits / 8)*(pCodecCtx->sample_rate)*(pCodecCtx->channels); fileSize = audioDataSize + 36; data = (int8_t *)"RIFF"; fwrite(data, sizeof(char), 4, audioFile); fwrite(&fileSize, sizeof(int32_t), 1, audioFile); data = (int8_t *)"WAVE"; fwrite(data, sizeof(char), 4, audioFile); data = (int8_t *)"fmt "; fwrite(data, sizeof(char), 4, audioFile); long_temp = 16; fwrite(&long_temp, sizeof(int32_t), 1, audioFile); short_temp = 0x01; fwrite(&short_temp, sizeof(int16_t), 1, audioFile); short_temp = (pCodecCtx->channels); fwrite(&short_temp, sizeof(int16_t), 1, audioFile); long_temp = (pCodecCtx->sample_rate); fwrite(&long_temp, sizeof(int32_t), 1, audioFile); long_temp = (bits / 8)*(pCodecCtx->channels)*(pCodecCtx->sample_rate); fwrite(&long_temp, sizeof(int32_t), 1, audioFile); BlockAlign = (bits / 8)*(pCodecCtx->channels); fwrite(&BlockAlign, sizeof(int16_t), 1, audioFile); short_temp = (bits); fwrite(&short_temp, sizeof(int16_t), 1, audioFile); data = (int8_t *) "data"; fwrite(data, sizeof(char), 4, audioFile); fwrite(&audioDataSize, sizeof(int32_t), 1, audioFile); }