#include "player.h"
#include "packet.h"
#include "frame.h"
static void sdl_audio_callback(void* opaque, Uint8* stream, int len);
// 从packet_queue中取一个packet,解码生成frame
static int audio_decode_frame(AVCodecContext* p_codec_ctx, packet_queue_t* p_pkt_queue, AVFrame* frame)
{
int ret;
while (1)
{
AVPacket pkt;
while (1)
{
//if (d->queue->abort_request)
// return -1;
// 3.2 一个音频packet含一至多个音频frame,每次avcodec_receive_frame()返回一个frame,此函数返回。
// 下次进来此函数,继续获取一个frame,直到avcodec_receive_frame()返回AVERROR(EAGAIN),
// 表示解码器需要填入新的音频packet
ret = avcodec_receive_frame(p_codec_ctx, frame);
if (ret >= 0)
{
// 时基转换,从d->avctx->pkt_timebase时基转换到1/frame->sample_rate时基
AVRational tb = { 1, frame->sample_rate };
if (frame->pts != AV_NOPTS_VALUE)
{
frame->pts = av_rescale_q(frame->pts, p_codec_ctx->pkt_timebase, tb);
}
else
{
av_log(NULL, AV_LOG_WARNING, "frame->pts no\n");
}
return 1;
}
else if (ret == AVERROR_EOF)
{
av_log(NULL, AV_LOG_INFO, "audio avcodec_receive_frame(): the decoder has been flushed\n");
avcodec_flush_buffers(p_codec_ctx);
return 0;
}
else if (ret == AVERROR(EAGAIN))
{
// av_log(NULL, AV_LOG_INFO, "audio avcodec_receive_frame(): input is not accepted in the current state\n");
break;
}
else
{
av_log(NULL, AV_LOG_ERROR, "audio avcodec_receive_frame(): other errors\n");
continue;
}
}
// 1. 取出一个packet。使用pkt对应的serial赋值给d->pkt_serial
if (packet_queue_get(p_pkt_queue, &pkt, true) < 0)
{
return -1;
}
// packet_queue中第一个总是flush_pkt。每次seek操作会插入flush_pkt,更新serial,开启新的播放序列
if (pkt.data == NULL)
{
// 复位解码器内部状态/刷新内部缓冲区。当seek操作或切换流时应调用此函数。
avcodec_flush_buffers(p_codec_ctx);
}
else
{
// 2. 将packet发送给解码器
// 发送packet的顺序是按dts递增的顺序,如IPBBPBB
// pkt.pos变量可以标识当前packet在视频文件中的地址偏移
if (avcodec_send_packet(p_codec_ctx, &pkt) == AVERROR(EAGAIN))
{
av_log(NULL, AV_LOG_ERROR, "receive_frame and send_packet both returned EAGAIN, which is an API violation.\n");
}
av_packet_unref(&pkt);
}
}
}
// 音频解码线程:从音频packet_queue中取数据,解码后放入音频frame_queue
static int audio_decode_thread(void* arg)
{
player_stat_t* is = (player_stat_t*)arg;
AVFrame* p_frame = av_frame_alloc();
frame_t* af;
int got_frame = 0;
AVRational tb;
int ret = 0;
if (p_frame == NULL)
{
return AVERROR(ENOMEM);
}
while (1)
{
got_frame = audio_decode_frame(is->p_acodec_ctx, &is->audio_pkt_queue, p_frame);
if (got_frame < 0)
{
goto the_end;
}
if (got_frame)
{
tb = { 1, p_frame->sample_rate };
if (!(af = frame_queue_peek_writable(&is->audio_frm_queue)))
goto the_end;
af->pts = (p_frame->pts == AV_NOPTS_VALUE) ? NAN : p_frame->pts * av_q2d(tb);
af->pos = p_frame->pkt_pos;
//-af->serial = is->auddec.pkt_serial;
// 当前帧包含的(单个声道)采样数/采样率就是当前帧的播放时长
af->duration = av_q2d({ p_frame->nb_samples, p_frame->sample_rate });
// 将frame数据拷入af->frame,af->frame指向音频frame队列尾部
av_frame_move_ref(af->frame, p_frame);
// 更新音频frame队列大小及写指针
frame_queue_push(&is->audio_frm_queue);
}
}
the_end:
av_frame_free(&p_frame);
return ret;
}
int open_audio_stream(player_stat_t* is)
{
AVCodecContext* p_codec_ctx;
AVCodecParameters* p_codec_par = NULL;
const AVCodec* p_codec = NULL;
int ret;
// 1. 为音频流构建解码器AVCodecContext
// 1.1 获取解码器参数AVCodecParameters
p_codec_par = is->p_audio_stream->codecpar;
// 1.2 获取解码器
p_codec = avcodec_find_decoder(p_codec_par->codec_id);
if (p_codec == NULL)
{
av_log(NULL, AV_LOG_ERROR, "Cann't find codec!\n");
return -1;
}
// 1.3 构建解码器AVCodecContext
// 1.3.1 p_codec_ctx初始化:分配结构体,使用p_codec初始化相应成员为默认值
p_codec_ctx = avcodec_alloc_context3(p_codec);
if (p_codec_ctx == NULL)
{
av_log(NULL, AV_LOG_ERROR, "avcodec_alloc_context3() failed\n");
return -1;
}
// 1.3.2 p_codec_ctx初始化:p_codec_par ==> p_codec_ctx,初始化相应成员
ret = avcodec_parameters_to_context(p_codec_ctx, p_codec_par);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "avcodec_parameters_to_context() failed %d\n", ret);
return -1;
}
// 1.3.3 p_codec_ctx初始化:使用p_codec初始化p_codec_ctx,初始化完成
ret = avcodec_open2(p_codec_ctx, p_codec, NULL);
if (ret < 0)
{
av_log(NULL, AV_LOG_ERROR, "avcodec_open2() failed %d\n", ret);
return -1;
}
p_codec_ctx->pkt_timebase = is->p_audio_stream->time_base;
is->p_acodec_ctx = p_codec_ctx;
// 2. 创建视频解码线程
SDL_CreateThread(audio_decode_thread, "audio decode thread", is);
return 0;
}
static int audio_resample(player_stat_t* is, int64_t audio_callback_time)
{
int data_size, resampled_data_size;
AVChannelLayout dec_channel_layout;
av_unused double audio_clock0;
int wanted_nb_samples;
frame_t* af;
if (is->paused)
{
return -1;
}
#if defined(_WIN32)
while (frame_queue_nb_remaining(&is->audio_frm_queue) == 0)
{
if ((av_gettime_relative() - audio_callback_time) > 1000000LL * is->audio_hw_buf_size / is->audio_param_tgt.bytes_per_sec / 2)
return -1;
av_usleep(1000);
}
#endif
// 若队列头部可读,则由af指向可读帧
if (!(af = frame_queue_peek_readable(&is->audio_frm_queue)))
return -1;
frame_queue_next(&is->audio_frm_queue);
// 根据frame中指定的音频参数获取缓冲区的大小
data_size = av_samples_get_buffer_size(NULL, af->frame->ch_layout.nb_channels, // 本行两参数:linesize,声道数
af->frame->nb_samples, // 本行一参数:本帧中包含的单个声道中的样本数
(AVSampleFormat)af->frame->format, 1); // 本行两参数:采样格式,不对齐
// 获取声道布局
//av_channel_layout_default(&dec_channel_layout, af->frame->ch_layout.nb_channels);
//af->frame->ch_layout &&
//dec_channel_layout =
// (af->frame->channel_layout && af->frame->channels ==
// av_get_channel_layout_nb_channels(af->frame->channel_layout)) ?
// af->frame->channel_layout : av_get_default_channel_layout(af->frame->channels);
dec_channel_layout = af->frame->ch_layout;
wanted_nb_samples = af->frame->nb_samples;
// is->audio_param_tgt是SDL可接受的音频帧数,是audio_open()中取得的参数
// 在audio_open()函数中又有“is->audio_src = is->audio_param_tgt”
// 此处表示:如果frame中的音频参数 == is->audio_src == is->audio_param_tgt,那音频重采样的过程就免了(因此时is->swr_ctr是NULL)
// 否则使用frame(源)和is->audio_param_tgt(目标)中的音频参数来设置is->swr_ctx,并使用frame中的音频参数来赋值is->audio_src
if (af->f
没有合适的资源?快使用搜索试试~ 我知道了~
音视频 ffmpeg 简单的播放器
共294个文件
h:231个
lib:11个
dll:9个
需积分: 32 5 下载量 138 浏览量
2022-10-19
15:43:17
上传
评论
收藏 83MB ZIP 举报
温馨提示
使用ffmpeg5.1编写的简单的播放器
资源详情
资源评论
资源推荐
收起资源包目录
音视频 ffmpeg 简单的播放器 (294个子文件)
libavutil.dll.a 376KB
libavfilter.dll.a 160KB
libavformat.dll.a 137KB
libavcodec.dll.a 110KB
libswscale.dll.a 22KB
libswresample.dll.a 17KB
libavdevice.dll.a 13KB
libpostproc.dll.a 7KB
SDL_config.h.cmake 18KB
audio.cpp 18KB
video.cpp 18KB
player.cpp 7KB
demux.cpp 6KB
frame.cpp 4KB
packet.cpp 3KB
main.cpp 237B
Browse.VC.db 14.01MB
avutil-57.def 13KB
avcodec-59.def 4KB
avformat-59.def 4KB
avfilter-8.def 2KB
swscale-6.def 746B
avdevice-59.def 544B
swresample-4.def 519B
postproc-56.def 223B
avcodec-59.dll 67.56MB
avfilter-8.dll 36.58MB
avformat-59.dll 14.9MB
avdevice-59.dll 3.63MB
SDL2.dll 2.34MB
avutil-57.dll 1.11MB
swscale-6.dll 659KB
swresample-4.dll 426KB
postproc-56.dll 132KB
simple_player.vcxproj.filters 2KB
SDL_opengl_glext.h 714KB
avcodec.h 111KB
avformat.h 111KB
SDL_egl.h 104KB
SDL_hints.h 101KB
SDL_opengles2_gl2ext.h 96KB
SDL_opengl.h 81KB
SDL_video.h 77KB
SDL_render.h 72KB
SDL_audio.h 58KB
SDL_events.h 46KB
avfilter.h 43KB
SDL_haptic.h 42KB
SDL_gamecontroller.h 38KB
SDL_joystick.h 37KB
pixfmt.h 36KB
opt.h 36KB
SDL_surface.h 36KB
SDL_opengles2_gl2.h 31KB
frame.h 31KB
avio.h 31KB
channel_layout.h 31KB
SDL_stdinc.h 29KB
SDL_rwops.h 27KB
swresample.h 25KB
SDL_pixels.h 24KB
hwcontext.h 24KB
packet.h 23KB
mem.h 23KB
SDL_system.h 20KB
intreadwrite.h 18KB
avdevice.h 18KB
SDL_hidapi.h 17KB
SDL_cpuinfo.h 17KB
SDL_thread.h 17KB
common.h 17KB
codec_id.h 17KB
SDL_mouse.h 17KB
SDL_scancode.h 16KB
swscale.h 15KB
SDL_keycode.h 15KB
avstring.h 15KB
pixdesc.h 15KB
fifo.h 15KB
SDL_atomic.h 14KB
SDL_mutex.h 14KB
codec.h 13KB
SDL_test_fuzzer.h 13KB
imgutils.h 13KB
SDL_rect.h 13KB
log.h 12KB
hdr_dynamic_metadata.h 12KB
SDL_assert.h 12KB
buffer.h 12KB
SDL_log.h 11KB
SDL_syswm.h 11KB
bsf.h 11KB
SDL_keyboard.h 11KB
samplefmt.h 10KB
SDL_opengles2_khrplatform.h 10KB
avutil.h 10KB
SDL_endian.h 10KB
SDL_config.h 9KB
hwcontext_vulkan.h 9KB
SDL_sensor.h 9KB
共 294 条
- 1
- 2
- 3
都市无名者
- 粉丝: 0
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论0