Skip to content

Instantly share code, notes, and snippets.

@ShadowPower
Created July 5, 2023 03:02
Show Gist options
  • Save ShadowPower/2a2908b28735d6174446c73ac872d70d to your computer and use it in GitHub Desktop.
Save ShadowPower/2a2908b28735d6174446c73ac872d70d to your computer and use it in GitHub Desktop.
ffmpeg playback with c++
#include "player.h"
using namespace std;
void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount) {
AVAudioFifo* fifo = reinterpret_cast<AVAudioFifo*>(pDevice->pUserData);
av_audio_fifo_read(fifo, &pOutput, frameCount);
(void) pInput;
}
int main(int argc, char* argv[])
{
if (argc < 2) {
cerr << "没有文件" << endl;
return -1;
}
// 打开文件
cout << "打开文件" << endl;
AVFormatContext* fmt_ctx{ nullptr };
int ret = avformat_open_input(&fmt_ctx, argv[1], nullptr, nullptr);
if (ret < 0) {
cerr << "打不开文件" << endl;
return -1;
}
cout << "找音视频流" << endl;
ret = avformat_find_stream_info(fmt_ctx, nullptr);
if (ret < 0) {
cerr << "文件里没有音视频流" << endl;
return -1;
}
cout << "文件里面有 " << fmt_ctx->nb_streams << " 条音视频流" << endl;
cout << "找音轨" << endl;
int index = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
if (index < 0) {
cerr << "没有音轨" << endl;
return -1;
}
AVStream* stream = fmt_ctx->streams[index];
cout << "找对应的解码器" << endl;
const AVCodec* decoder = avcodec_find_decoder(stream->codecpar->codec_id);
if (!decoder) {
cerr << "没有解码器" << endl;
return -1;
}
cout << "创建解码器" << endl;
AVCodecContext* codec_ctx{ avcodec_alloc_context3(decoder) };
avcodec_parameters_to_context(codec_ctx, stream->codecpar);
ret = avcodec_open2(codec_ctx, decoder, nullptr);
if (ret < 0) {
cerr << "解码器创建失败" << endl;
return -1;
}
// 解码
AVPacket* packet = av_packet_alloc();
AVFrame* frame = av_frame_alloc();
AVCodecParameters* codec_par = stream->codecpar;
SwrContext* resampler{swr_alloc_set_opts(nullptr, codec_par->channel_layout, AV_SAMPLE_FMT_FLT,
codec_par->sample_rate, codec_par->channel_layout, (AVSampleFormat) codec_par->format,
codec_par->sample_rate, 0, nullptr)};
AVAudioFifo* fifo = av_audio_fifo_alloc(AV_SAMPLE_FMT_FLT, codec_par->channels, 1);
while (av_read_frame(fmt_ctx, packet) == 0) {
if (packet->stream_index != stream->index) {
continue;
}
cout << "将音频帧放进解码队列" << endl;
ret = avcodec_send_packet(codec_ctx, packet);
if (ret < 0) {
if (ret != AVERROR(EAGAIN)) {
cerr << "炸了" << endl;
}
}
while ((ret = avcodec_receive_frame(codec_ctx, frame)) == 0) {
cout << "从解码队列中取出解码结果" << endl;
if (ret < 0) {
if (ret == AVERROR(AVERROR_EOF)) {
// 放完了
break;
}
// 其他问题
break;
}
cout << "重采样PCM转成所需要的格式" << endl;
AVFrame* resampled_frame = av_frame_alloc();
resampled_frame->sample_rate = frame->sample_rate;
resampled_frame->channel_layout = frame->channel_layout;
resampled_frame->channels = frame->channels;
resampled_frame->format = AV_SAMPLE_FMT_FLT;
ret = swr_convert_frame(resampler, resampled_frame, frame);
cout << "写进FIFO队列" << endl;
av_frame_unref(frame);
av_audio_fifo_write(fifo, (void**)resampled_frame->data, resampled_frame->nb_samples);
av_frame_free(&resampled_frame);
}
}
// 播放
ma_device_config deviceConfig;
ma_device device;
ma_backend backends[] = {
ma_backend_wasapi
};
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.format = ma_format_f32;
deviceConfig.playback.channels = codec_par->channels;
deviceConfig.sampleRate = codec_par->sample_rate;
deviceConfig.dataCallback = data_callback;
deviceConfig.pUserData = fifo;
cout << "释放FFMPEG内存" << endl;
avformat_close_input(&fmt_ctx);
av_frame_free(&frame);
av_packet_free(&packet);
avcodec_free_context(&codec_ctx);
swr_free(&resampler);
cout << "初始化音频设备" << endl;
if (ma_device_init_ex(backends, sizeof(backends) / sizeof(backends[0]), NULL, &deviceConfig, &device) != MA_SUCCESS) {
cerr << "无法初始化音频设备" << endl;
return -1;
}
cout << "打开音频设备" << endl;
if (ma_device_start(&device) != MA_SUCCESS) {
cerr << "音频设备打开失败" << endl;
ma_device_uninit(&device);
return -1;
}
while (av_audio_fifo_size(fifo));
cout << "释放FIFO队列内存" << endl;
av_audio_fifo_free(fifo);
cout << "关闭音频设备" << endl;
ma_device_uninit(&device);
getchar();
return 0;
}
#pragma once
#include <iostream>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/audio_fifo.h>
#include <libswresample/swresample.h>
}
#define MINIAUDIO_IMPLEMENTATION
#include "miniaudio.h"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment