• win api + ffmpeg 播放 mp3 音乐


      暂时记录,还有很多需要改善的地方一直没弄好,比如不知道怎么对上正确的播放速度。

      有一些多余的代码,不用在意。

    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <string>
    #include <windows.h>
    #include <Mmreg.h>
    #include <mmeapi.h>
    #include <Windows.h>
    #include <fftw3.h>
    #include <math.h>
    
    extern "C" {
    #include "libavcodec/avcodec.h"
    #include "libavutil/opt.h"
    #include "libavformat/avformat.h"
    #include "libswresample/swresample.h"
    #include "libavutil/mathematics.h"
    }
    
    #pragma comment(lib, "C:/Program Files/ffmpeg/lib/avcodec.lib")
    #pragma comment(lib, "C:/Program Files/ffmpeg/lib/avformat.lib")
    #pragma comment(lib, "C:/Program Files/ffmpeg/lib/avutil.lib")
    #pragma comment(lib, "C:/Program Files/ffmpeg/lib/avdevice.lib")
    #pragma comment(lib, "C:/Program Files/ffmpeg/lib/swresample.lib")
    
    #pragma comment(lib, "Winmm.lib")
    #pragma comment(lib, "C:/fftw/libfftw3-3.lib")
    #pragma comment(lib, "C:/fftw/libfftw3f-3.lib")
    #pragma comment(lib, "C:/fftw/libfftw3l-3.lib")
    
    // #pragma comment(lib, "C:/opencv-4.1.2/build/install/x64/vc16/lib/opencv_world412d.lib")
    
    #pragma warning(disable:4996)
    
    #define RATE 44100
    #define PIPE 2
    #define PI 3.1415926
    #define INBUF_SIZE 4096
    #define AUDIO_INBUF_SIZE 20480
    #define AUDIO_REFILL_THRESH 4096
    #define AV_CODEC_MAX_AUDIO_FRAME_SIZE 16384
    #define MAX_AUDIO_FRAME_SIZE 320000
    #define SECOND 35
    
    int decode_audio_file(HWAVEOUT hWavO, WAVEHDR whr, WAVEHDR whr2, const char* filename)
    {
    	av_register_all();
    	avformat_network_init();
    	
    	AVFormatContext* format = avformat_alloc_context();
    	if (avformat_open_input(&format, filename, NULL, NULL) != 0) {
    		fprintf(stderr, "Could not open file '%s'
    ", filename);
    		return -1;
    	}
    	if (avformat_find_stream_info(format, NULL) < 0) {
    		fprintf(stderr, "Could not retrieve stream info from file '%s'
    ", filename);
    		return -1;
    	}
    
    	av_dump_format(format, 0, filename, false);
    
    	// Find the index of the first audio stream
    	int stream_index = -1;
    	for (int i = 0; i < format->nb_streams; i++)
    	{
    		if (format->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
    			stream_index = i;
    			break;
    		}
    	}
    	if (stream_index == -1)
    	{
    		fprintf(stderr, "Could not retrieve audio stream from file '%s'
    ", filename);
    		return -1;
    	}
    	AVStream* stream = format->streams[stream_index];
    
    	// find & open codec
    	AVCodecContext* codec = stream->codec;
    	if (avcodec_open2(codec, avcodec_find_decoder(codec->codec_id), NULL) < 0)
    	{
    		fprintf(stderr, "Failed to open decoder for stream #%u in file '%s'
    ", stream_index, filename);
    		return -1;
    	}
    
    	// prepare to read data
    	AVPacket * packet = (AVPacket*)av_malloc(sizeof(AVPacket));
    	av_init_packet(packet);
    
    	AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
    	
    	int out_channels_layout = AV_CH_LAYOUT_STEREO;
    	int out_channels = av_get_channel_layout_nb_channels(out_channels_layout);
    	int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, codec->frame_size, out_sample_fmt, 1);
    	PBYTE buffer = (uint8_t*)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);
    
    	AVFrame* frame = av_frame_alloc();
    	if (!frame)
    	{
    		fprintf(stderr, "Error allocating the frame
    ");
    		return -1;
    	}
    	// prepare resampler
    	struct SwrContext* swr = swr_alloc();
    
    	av_opt_set_int(swr, "in_channel_count", codec->channels, 0);
    	av_opt_set_int(swr, "out_channel_count", 2, 0);
    	av_opt_set_int(swr, "in_channel_layout", av_get_default_channel_layout(codec->channels), 0);
    	av_opt_set_int(swr, "out_channel_layout", out_channels_layout, 0);
    	av_opt_set_int(swr, "in_sample_rate", codec->sample_rate, 0);
    	av_opt_set_int(swr, "out_sample_rate", codec->sample_rate, 0);
    	av_opt_set_sample_fmt(swr, "in_sample_fmt", codec->sample_fmt, 0);
    	av_opt_set_sample_fmt(swr, "out_sample_fmt", out_sample_fmt, 0);
    	swr_init(swr);
    	if (!swr_is_initialized(swr)) {
    		fprintf(stderr, "Resampler has not been properly initialized
    ");
    		return -1;
    	}
    
    	whr.lpData = (LPSTR)buffer;
    	whr.dwBufferLength = out_buffer_size;
    	waveOutPrepareHeader(hWavO, &whr, sizeof(whr));
    
    	whr2.lpData = (LPSTR)buffer;
    	whr2.dwBufferLength = out_buffer_size;
    	waveOutPrepareHeader(hWavO, &whr2, sizeof(whr2));
    
    	// iterate through frames
    	while (av_read_frame(format, packet) >= 0) {
    		if (packet->stream_index == stream_index)
    		{
    			int gotFrame;
    			if (avcodec_decode_audio4(codec, frame, &gotFrame, packet) < 0) {
    				break;
    			}
    			if (gotFrame > 0)
    			{
    				int frame_count = swr_convert(swr, &buffer,
    					MAX_AUDIO_FRAME_SIZE,
    					(const uint8_t**)frame->data,
    					frame->nb_samples);
    
    				
    				for (int i = 0; i < codec->sample_rate * SECOND; i++)
    				{
    					waveOutWrite(hWavO, &whr, sizeof(whr));
    				}
    
    				
    				for (int i = 0; i < codec->sample_rate * SECOND; i++)
    				{
    					waveOutWrite(hWavO, &whr2, sizeof(whr2));
    				}
    			}
    		}
    		av_free_packet(packet);
    	}
    	
    	// clean up
    	av_free(buffer);
    	av_frame_free(&frame);
    	swr_free(&swr);
    	avcodec_close(codec);
    	avformat_free_context(format);
    
    	return 0;
    }
    
    int audio_decode(/*const char * outfilename, */HWAVEOUT hWavO, WAVEHDR whr, WAVEHDR whr2, const char * filename)
    {
    	AVFormatContext* pFormatCtx;
    	AVCodecContext* pCodecCtx;
    	AVCodec* pCodec;
    	AVPacket* packet;
    	uint8_t* out_buffer;
    	AVFrame* pFrame;
    	int	audioStream;
    	int got_picture;
    	int index = 0;
    	struct SwrContext* au_convert_ctx;
    
    	//FILE* pFile = pFile = fopen(outfilename, "wb");
    
    	av_register_all();
    	avformat_network_init();
    	pFormatCtx = avformat_alloc_context();
    
    	if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0) {
    		printf("Couldn't open input stream.
    ");
    		return -1;
    	}
    	// Retrieve stream information
    	if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
    		printf("Couldn't find stream information.
    ");
    		return -1;
    	}
    	// Dump valid information onto standard error
    	av_dump_format(pFormatCtx, 0, filename, false);
    
    	// Find the first audio stream
    	audioStream = -1;
    	for (int i = 0; i < pFormatCtx->nb_streams; i++)
    		if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
    			audioStream = i;
    			break;
    		}
    
    	if (audioStream == -1) {
    		printf("Didn't find a audio stream.
    ");
    		return -1;
    	}
    
    	// Get a pointer to the codec context for the audio stream
    	pCodecCtx = pFormatCtx->streams[audioStream]->codec;
    
    	// Find the decoder for the audio stream
    	pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    	if (pCodec == NULL) {
    		printf("Codec not found.
    ");
    		return -1;
    	}
    
    	// Open codec
    	if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
    		printf("Could not open codec.
    ");
    		return -1;
    	}
    
    	packet = (AVPacket*)av_malloc(sizeof(AVPacket));
    	av_init_packet(packet);
    
    	//Out Audio Param
    	uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;
    	//nb_samples: AAC-1024 MP3-1152
    	int out_nb_samples = pCodecCtx->frame_size;
    	AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
    	int out_sample_rate = pCodecCtx->sample_rate;
    	int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);
    	//Out Buffer Size
    	int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);
    
    	out_buffer = (uint8_t*)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);
    	pFrame = av_frame_alloc();
    
    
    	//FIX:Some Codec's Context Information is missing
    	int64_t in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);
    	//Swr
    
    	au_convert_ctx = swr_alloc();
    	au_convert_ctx = swr_alloc_set_opts(au_convert_ctx,
    		out_channel_layout,
    		out_sample_fmt,
    		out_sample_rate,
    		in_channel_layout,
    		pCodecCtx->sample_fmt,
    		pCodecCtx->sample_rate, 0, NULL);
    	swr_init(au_convert_ctx);
    
    	whr.lpData = (LPSTR)out_buffer;
    	whr.dwBufferLength = out_buffer_size;
    	waveOutPrepareHeader(hWavO, &whr, sizeof(whr));
    
    	whr2.lpData = (LPSTR)out_buffer;
    	whr2.dwBufferLength = out_buffer_size;
    	waveOutPrepareHeader(hWavO, &whr2, sizeof(whr2));
    	//waveOutSetPlaybackRate(hWavO, 0x8000); 本来想用来调节播放速率 但用了之后发现只能变声,不知道为啥
    
    	while (av_read_frame(pFormatCtx, packet) >= 0) {
    		if (packet->stream_index == audioStream) {
    			int ret = avcodec_decode_audio4(pCodecCtx, pFrame, &got_picture, packet);
    			if (ret < 0) {
    				printf("Error in decoding audio frame.
    ");
    				return -1;
    			}
    			if (got_picture > 0) {
    				swr_convert(au_convert_ctx, &out_buffer,
    					MAX_AUDIO_FRAME_SIZE, (const uint8_t**)pFrame->data,
    					pFrame->nb_samples);
    #if SHOW
    				printf("index:%5d	 pts:%lld	 packet size:%d
    ", index, packet->pts, packet->size);
    #endif
    
    				//fwrite(out_buffer, 1, out_buffer_size, pFile);
    				
    				for (int i = 0; i < pCodecCtx->sample_rate * SECOND; i++)
    				{
    					waveOutWrite(hWavO, &whr, sizeof(whr));
    				}
    
    				
    				for (int i = 0; i < pCodecCtx->sample_rate * SECOND; i++)
    				{
    					waveOutWrite(hWavO, &whr2, sizeof(whr2));
    				}
    				
    				index++;
    			}
    
    		}
    		av_free_packet(packet);
    	}
    
    	swr_free(&au_convert_ctx);
    
    	//fclose(pFile);
    
    	av_free(out_buffer);
    	avcodec_close(pCodecCtx);
    	avformat_close_input(&pFormatCtx);
    	return 0;
    }
    
    void GenerateAudio(HWAVEOUT hWavO, WAVEHDR whr)
    {
    	double freq[] = { 261.625, 293.664, 329.627, 349.228, 391.995, 440, 493.883, 523.251 };
    	PBYTE buffer = new BYTE[RATE * SECOND];
    	for (int j = 0; j < 8; j++)
    	{
    		double w = (2 * PI) / freq[j];
    		for (int i = 0; i < RATE * SECOND; i++)
    		{
    			buffer[i] = 127 + 127 * std::sin(w * i);
    		}
    		
    		whr.lpData = (LPSTR)buffer;
    		whr.dwBufferLength = RATE * SECOND;
    		waveOutPrepareHeader(hWavO, &whr, sizeof(whr));
    		for (int i = 0; i < RATE; i++)
    			waveOutWrite(hWavO, &whr, sizeof(whr));
    	}
    	delete[] buffer;
    }
    
    int main()
    {
    	WAVEHDR whr, whr2;
    	WAVEFORMATEX wfx;
    	HWAVEOUT hWavO;
    
    	wfx.wFormatTag = WAVE_FORMAT_PCM;
    	wfx.nSamplesPerSec = RATE;
    	wfx.nChannels = PIPE;
    	wfx.wBitsPerSample = 16;
    	wfx.nBlockAlign = PIPE * wfx.wBitsPerSample / 8;
    	wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
    	wfx.cbSize = 0;
    
    
    	if (waveOutOpen(&hWavO, WAVE_MAPPER, &wfx, NULL, 0, CALLBACK_NULL) != MMSYSERR_NOERROR)
    		std::cout << "出错";
    
    	whr.dwLoops = 1;
    	whr.dwFlags = 0;
    	whr2.dwLoops = 1;
    	whr2.dwFlags = 0;
    
    	
    	//GenerateAudio(hWavO, whr);
    	//audio_decode(hWavO, whr, whr2, "E:/CloudMusic/xxx.mp3");
    	decode_audio_file(hWavO, whr, whr2, "E:/CloudMusic/xxx.mp3");
    
    	waveOutUnprepareHeader(hWavO, &whr, sizeof(whr));
    	waveOutUnprepareHeader(hWavO, &whr2, sizeof(whr2));
    	waveOutClose(hWavO);
    	return 0;
    }
    

      

  • 相关阅读:
    tcp发送缓冲区中的数据都是由产生数据的进程给推送到ip层还是有定时任务触发?
    发生dev_queue_xmit的时候,全部都是从ip_finish_output中来的吗
    网络控制API 路由表 arp表 包括tcp的这些参数都是从哪里设置
    dev_queue_xmit 发生了什么?skb还会在哪里缓存
    内核blackhole
    网卡多ip 再看arp; arp队列也会缓存skb
    tcp发送缓冲区中的数据都是由产生数据的进程给推送到ip层还是有定时任务触发?
    socket有没有同步写一说(怎么判定数据一定达到了对端?还得用户态)
    貌似要看看时钟了
    读写JSON作配置文件
  • 原文地址:https://www.cnblogs.com/darkchii/p/11957694.html
Copyright © 2020-2023  润新知