赞
踩
1、包含必须的头文件。
- #include <iostream>
- extern "C" {
- #include <libavformat/avformat.h>
- #include <libswresample/swresample.h>
- #include <libavutil/opt.h>
- #include <libavutil/audio_fifo.h>
- #include <libavutil/frame.h>
- }
-
- // SDL相关头文件
- #include <SDL2/SDL.h>
- #include <SDL2/SDL_audio.h>
2、示例。
- #define AUDIO_BUFFER_SIZE 4096
-
- typedef struct {
- uint8_t* buffer;
- int size;
- int pos;
- } AudioParams;
-
- void audio_callback(void* userdata, Uint8* stream, int len) {
- AudioParams* audioParams = (AudioParams*)userdata;
- if (audioParams->pos >= audioParams->size) {
- return;
- }
- int remaining = audioParams->size - audioParams->pos;
- len = (len > remaining) ? remaining : len;
- memcpy(stream, audioParams->buffer + audioParams->pos, len);
- audioParams->pos += len;
- }
-
- int main() {
- AVFormatContext* formatContext = avformat_alloc_context();
-
- // 打开输入文件
- if (avformat_open_input(&formatContext, "input.mp4", NULL, NULL) != 0) {
- std::cerr << "无法打开输入文件" << std::endl;
- return -1;
- }
-
- // 检索流信息
- if (avformat_find_stream_info(formatContext, NULL) < 0) {
- std::cerr << "无法检索流信息" << std::endl;
- return -1;
- }
-
- // 寻找音频流和视频流
- int audioStreamIndex = -1;
- int videoStreamIndex = -1;
-
- for (unsigned int i = 0; i < formatContext->nb_streams; i++) {
- if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
- audioStreamIndex = i;
- }
- else if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
- videoStreamIndex = i;
- }
- }
-
- // 检查是否找到音频流和视频流
- if (audioStreamIndex == -1 || videoStreamIndex == -1) {
- std::cerr << "无法找到音频流或视频流" << std::endl;
- return -1;
- }
-
- // 获取音频解码器和视频解码器
- AVCodecParameters* audioCodecParameters = formatContext->streams[audioStreamIndex]->codecpar;
- AVCodecParameters* videoCodecParameters = formatContext->streams[videoStreamIndex]->codecpar;
-
- AVCodec* audioCodec = avcodec_find_decoder(audioCodecParameters->codec_id);
- AVCodec* videoCodec = avcodec_find_decoder(videoCodecParameters->codec_id);
-
- // 打开音频解码器和视频解码器
- AVCodecContext* audioCodecContext = avcodec_alloc_context3(audioCodec);
- AVCodecContext* videoCodecContext = avcodec_alloc_context3(videoCodec);
-
- if (!audioCodecContext || !videoCodecContext) {
- std::cerr << "无法分配解码器上下文" << std::endl;
- return -1;
- }
-
- if (avcodec_parameters_to_context(audioCodecContext, audioCodecParameters) < 0 ||
- avcodec_parameters_to_context(videoCodecContext, videoCodecParameters) < 0) {
- std::cerr << "无法填充解码器上下文" << std::endl;
- return -1;
- }
-
- if (avcodec_open2(audioCodecContext, audioCodec, NULL) < 0 ||
- avcodec_open2(videoCodecContext, videoCodec, NULL) < 0) {
- std::cerr << "无法打开解码器" << std::endl;
- return -1;
- }
-
- // 初始化SDL
- if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0) {
- std::cerr << "无法初始化SDL" << std::endl;
- return -1;
- }
-
- // 创建窗口和渲染器
- SDL_Window* window = SDL_CreateWindow("Video Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
- videoCodecParameters->width, videoCodecParameters->height, SDL_WINDOW_SHOWN);
- SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
- SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING,
- videoCodecParameters->width, videoCodecParameters->height);
-
- // 音频参数设置
- AudioParams audioParams;
- audioParams.buffer = new uint8_t[AUDIO_BUFFER_SIZE];
- audioParams.size = AUDIO_BUFFER_SIZE;
- audioParams.pos = 0;
-
- // 初始化音频重采样上下文
- SwrContext* swrContext = swr_alloc_set_opts(NULL,
- av_get_default_channel_layout(audioCodecContext->channels),
- AV_SAMPLE_FMT_S16,
- audioCodecContext->sample_rate,
- av_get_default_channel_layout(audioCodecContext->channels),
- audioCodecContext->sample_fmt,
- audioCodecContext->sample_rate,
- 0, NULL);
- if (!swrContext) {
- std::cerr << "无法分配音频重采样上下文" << std::endl;
- return -1;
- }
-
- if (swr_init(swrContext) < 0) {
- std::cerr << "无法初始化音频重采样上下文" << std::endl;
- return -1;
- }
-
- // 打开音频设备
- SDL_AudioSpec desiredSpec, obtainedSpec;
- desiredSpec.freq = audioCodecContext->sample_rate;
- desiredSpec.format = AUDIO_S16SYS;
- desiredSpec.channels = audioCodecContext->channels;
- desiredSpec.silence = 0;
- desiredSpec.samples = 1024;
- desiredSpec.callback = audio_callback;
- desiredSpec.userdata = &audioParams;
-
- if (SDL_OpenAudio(&desiredSpec, &obtainedSpec) < 0) {
- std::cerr << "无法打开音频设备" << std::endl;
- return -1;
- }
-
- // 开始播放音频
- SDL_PauseAudio(0);
-
- // 循环读取帧数据并播放
- AVPacket packet;
- AVFrame* frame = av_frame_alloc();
- AVFrame* convertedFrame = av_frame_alloc();
-
- while (av_read_frame(formatContext, &packet) >= 0) {
- if (packet.stream_index == audioStreamIndex) {
- // 解码音频帧
- int ret = avcodec_send_packet(audioCodecContext, &packet);
-
- if (ret < 0) {
- std::cerr << "无法发送音频数据包" << std::endl;
- break;
- }
-
- while (ret >= 0) {
- ret = avcodec_receive_frame(audioCodecContext, frame);
-
- if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
- break;
- }
- else if (ret < 0) {
- std::cerr << "无法解码音频帧" << std::endl;
- break;
- }
-
- // 音频重采样
- int dst_nb_samples = av_rescale_rnd(swr_get_delay(swrContext, frame->sample_rate) +
- frame->nb_samples,
- audioCodecContext->sample_rate,
- frame->sample_rate,
- AV_ROUND_UP);
- av_frame_make_writable(convertedFrame);
- convertedFrame->format = AV_SAMPLE_FMT_S16;
- convertedFrame->channel_layout = audioCodecContext->channel_layout;
- convertedFrame->sample_rate = audioCodecContext->sample_rate;
- convertedFrame->channels = audioCodecContext->channels;
- av_samples_alloc(convertedFrame->data, convertedFrame->linesize, audioCodecContext->channels,
- dst_nb_samples, AV_SAMPLE_FMT_S16, 0);
- swr_convert(swrContext, convertedFrame->data, dst_nb_samples,
- (const uint8_t**)frame->data, frame->nb_samples);
-
- // 播放音频
- int dataSize = av_get_bytes_per_sample((AVSampleFormat)convertedFrame->format) *
- convertedFrame->nb_samples * convertedFrame->channels;
-
- if (audioParams.pos + dataSize <= audioParams.size) {
- memcpy(audioParams.buffer + audioParams.pos, convertedFrame->data[0], dataSize);
- audioParams.pos += dataSize;
- }
-
- av_freep(&convertedFrame->data[0]);
- }
- }
- else if (packet.stream_index == videoStreamIndex) {
- // 解码视频帧
- int ret = avcodec_send_packet(videoCodecContext, &packet);
-
- if (ret < 0) {
- std::cerr << "无法发送视频数据包" << std::endl;
- // 音频参数设置
- AudioParams audioParams;
- audioParams.buffer = new uint8_t[AUDIO_BUFFER_SIZE];
- audioParams.size = AUDIO_BUFFER_SIZE;
- audioParams.pos = 0;
-
- // 初始化音频重采样上下文
- SwrContext* swrContext = swr_alloc_set_opts(NULL,
- av_get_default_channel_layout(audioCodecContext->channels),
- AV_SAMPLE_FMT_S16,
- audioCodecContext->sample_rate,
- av_get_default_channel_layout(audioCodecContext->channels),
- audioCodecContext->sample_fmt,
- audioCodecContext->sample_rate,
- 0, NULL);
- if (!swrContext) {
- std::cerr << "无法分配音频重采样上下文" << std::endl;
- return -1;
- }
-
- if (swr_init(swrContext) < 0) {
- std::cerr << "无法初始化音频重采样上下文" << std::endl;
- return -1;
- }
-
- // 打开音频设备
- SDL_AudioSpec desiredSpec, obtainedSpec;
- desiredSpec.freq = audioCodecContext->sample_rate;
- desiredSpec.format = AUDIO_S16SYS;
- desiredSpec.channels = audioCodecContext->channels;
- desiredSpec.silence = 0;
- desiredSpec.samples = 1024;
- desiredSpec.callback = audio_callback;
- desiredSpec.userdata = &audioParams;
-
- if (SDL_OpenAudio(&desiredSpec, &obtainedSpec) < 0) {
- std::cerr << "无法打开音频设备" << std::endl;
- return -1;
- }
-
- // 开始播放音频
- SDL_PauseAudio(0);
-
- // 循环读取帧数据并播放
- AVPacket packet;
- AVFrame* frame = av_frame_alloc();
- AVFrame* convertedFrame = av_frame_alloc();
-
- while (av_read_frame(formatContext, &packet) >= 0) {
- if (packet.stream_index == audioStreamIndex) {
- // 解码音频帧
- int ret = avcodec_send_packet(audioCodecContext, &packet);
-
- if (ret < 0) {
- std::cerr << "无法发送音频数据包" << std::endl;
- break;
- }
-
- while (ret >= 0) {
- ret = avcodec_receive_frame(audioCodecContext, frame);
-
- if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
- break;
- }
- else if (ret < 0) {
- std::cerr << "无法解码音频帧" << std::endl;
- break;
- }
-
- // 音频重采样
- int dst_nb_samples = av_rescale_rnd(swr_get_delay(swrContext, frame->sample_rate) +
- frame->nb_samples,
- audioCodecContext->sample_rate,
- frame->sample_rate,
- AV_ROUND_UP);
- av_frame_make_writable(convertedFrame);
- convertedFrame->format = AV_SAMPLE_FMT_S16;
- convertedFrame->channel_layout = audioCodecContext->channel_layout;
- convertedFrame->sample_rate = audioCodecContext->sample_rate;
- convertedFrame->channels = audioCodecContext->channels;
- av_samples_alloc(convertedFrame->data, convertedFrame->linesize, audioCodecContext->channels,
- dst_nb_samples, AV_SAMPLE_FMT_S16, 0);
- swr_convert(swrContext, convertedFrame->data, dst_nb_samples,
- (const uint8_t**)frame->data, frame->nb_samples);
-
- // 播放音频
- int dataSize = av_get_bytes_per_sample((AVSampleFormat)convertedFrame->format) *
- convertedFrame->nb_samples * convertedFrame->channels;
-
- if (audioParams.pos + dataSize <= audioParams.size) {
- memcpy(audioParams.buffer + audioParams.pos, convertedFrame->data[0], dataSize);
- audioParams.pos += dataSize;
- }
-
- av_freep(&convertedFrame->data[0]);
- }
- }
- else if (packet.stream_index == videoStreamIndex) {
- // 解码视频帧
- int ret = avcodec_send_packet(videoCodecContext, &packet);
-
- if (ret < 0) {
- std::cerr << "无法发送视频数据包" << std::endl;
- break;
- }
- while (ret >= 0) {
- ret = avcodec_receive_frame(videoCodecContext, frame);
-
- if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
- break;
- }
- else if (ret < 0) {
- std::cerr << "无法解码视频帧" << std::endl;
- break;
- }
-
- // 渲染视频
- SDL_UpdateTexture(texture, NULL, frame->data[0], frame->linesize[0]);
- SDL_RenderClear(renderer);
- SDL_RenderCopy(renderer, texture, NULL, NULL);
- SDL_RenderPresent(renderer);
- }
- }
-
- av_packet_unref(&packet);
- }
-
- // 释放资源
- av_frame_free(&frame);
- av_frame_free(&convertedFrame);
- avcodec_close(audioCodecContext);
- avcodec_close(videoCodecContext);
- avformat_close_input(&formatContext);
- avformat_free_context(formatContext);
- swr_free(&swrContext);
- SDL_CloseAudio();
- SDL_Quit();
-
- return 0;
- }
- }
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。