/*=========================================================================\
* Copyright(C)2016 Chudai.
*
* File name : video.c
* Version : v1.0.0
* Author : 初代
* Date : 2016/10/07
* Description :
* Function list: 1.
* 2.
* 3.
* History :
\*=========================================================================*/
/*-----------------------------------------------------------*
* 头文件 *
*-----------------------------------------------------------*/
#include "video.h"
/*======================================================================\
* Author (作者): i.sshe
* Date (日期): 2016/10/07
* Others (其他): 一些准备工作
\*=======================================================================*/
int prepare_video(PlayerState *ps)
{
ps->pvideo_stream = ps->pformat_ctx->streams[ps->video_stream_index];
ps->pvideo_codec_ctx = ps->pvideo_stream->codec;
ps->pvideo_codec = avcodec_find_decoder(ps->pvideo_codec_ctx->codec_id);
if (ps->pvideo_codec == NULL)
{
fprintf(ERR_STREAM, "Couldn't find video decoder\n");
return (-1);
}
//打开解码器
if (avcodec_open2(ps->pvideo_codec_ctx, ps->pvideo_codec, NULL) < 0)
{
fprintf(ERR_STREAM, "Couldn't open video decoder\n");
return -1;
}
return 0;
}
/*======================================================================\
* Author (作者): i.sshe
* Date (日期): 2016/10/07
* Others (其他): 其实这里还算准备工作,开窗口什么的
\*=======================================================================*/
int play_video(PlayerState *ps)
{
printf("play video!!!\n");
ps->pixel_w = ps->pvideo_codec_ctx->width;
ps->pixel_h = ps->pvideo_codec_ctx->height;
ps->window_w = ps->pixel_w;
ps->window_h = ps->pixel_h;
ps->pixfmt = AV_PIX_FMT_YUV420P;
ps->out_frame.format = AV_PIX_FMT_YUV420P;
ps->out_frame.width = ps->pixel_w;
ps->out_frame.height = ps->pixel_h;
//
ps->video_buf = (uint8_t *)av_malloc(
avpicture_get_size(ps->pixfmt,
ps->out_frame.width, ps->out_frame.height)
);
//用av_image_fill_arrays代替。
//根据所给参数和提供的数据设置data指针和linesizes。
avpicture_fill((AVPicture *)&ps->out_frame, ps->video_buf,
ps->pixfmt,
ps->out_frame.width, ps->out_frame.height);
//使用sws_scale之前要用这个函数进行相关转换操作。
//分配和返回一个 SwsContext.
//sws_freeContext(ps->psws_ctx); 需要用这个函数free内存。
//现在因为只用了一次sws_getContext()所以,这个内存在main释放。
//因为一直输出格式什么都一样,所以没有放在靠近sws_scale的地方。
ps->psws_ctx = sws_getContext(ps->pixel_w,
ps->pixel_h, ps->pvideo_codec_ctx->pix_fmt,
ps->out_frame.width, ps->out_frame.height,
ps->pixfmt,
SWS_BILINEAR, NULL, NULL, NULL);
ps->sdl_rect.x = 0;
ps->sdl_rect.y = 0;
//创建窗口
//SDL_WINDOW_RESIZABLE: 使窗口可以拉伸
ps->pwindow = SDL_CreateWindow("Isshe Video Player!",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
ps->window_w, ps->window_h,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (ps->pwindow == NULL)
{
fprintf(ERR_STREAM, "Couldn't Create Window\n");
exit(-1); //
}
//新建一个渲染器
ps->prenderer = SDL_CreateRenderer(ps->pwindow, -1, 0);
ps->ptexture = SDL_CreateTexture(ps->prenderer,
SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,
ps->pixel_w, ps->pixel_h);
//新建线程运行刷新函数
SDL_CreateThread(refresh_fun, "refresh func", ps);
return 0;
}
/*======================================================================\
* Author (作者): i.sshe
* Date (日期): 2016/10/08
* Others (其他): 刷新函数
\*=======================================================================*/
int refresh_fun(void *arg)
{
SDL_Event event;
PlayerState *ps = (PlayerState*) arg;
while(ps->quit == 0)
{
event.type = ISSHE_REFRESH_EVENT;
SDL_PushEvent(&event);
SDL_Delay(ps->delay);
}
return 0;
}
/*======================================================================\
* Author (作者): i.sshe
* Date (日期): 2016/10/07
* Others (其他):
\*=======================================================================*/
int decode_and_show(void *arg)
{
printf("decode_video!!!\n");
PlayerState *ps = (PlayerState *)arg;
AVPacket packet ;
AVFrame *pframe = av_frame_alloc();
AVFrame *tempframe = av_frame_alloc();
double pts = 0.0;
int ret = 0;
// ...
if (ps->quit == 1)
return 0;
if (ps->video_packet_queue.nb_packets == 0)
{
return 0;
}
//从packet队列取一个packet出来解码
ret = packet_queue_get(&ps->video_packet_queue, &packet, 1);
if (ret < 0)
{
fprintf(ERR_STREAM, "Get video packet error\n");
return -1; //
}
ret = avcodec_send_packet(ps->pvideo_codec_ctx, &packet);
if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
{
fprintf(ERR_STREAM, "send video packet error\n");
return -1; //
}
ret = avcodec_receive_frame(ps->pvideo_codec_ctx, pframe);
if (ret < 0 && ret != AVERROR_EOF)
{
fprintf(ERR_STREAM, "receive video frame error\n");
return -1;
}
//下面三句实现音视频同步,还有一句在audio部分。
//获取pts
pts = get_frame_pts(ps, pframe);
//ps中用cur_frame_pts是为了减少get_delay()的参数
ps->cur_frame_pts = pts; //*(double *)pframe.opaque;
ps->delay = get_delay(ps) * 1000 + 0.5;
printf("video frame pts = %lf\n", pts);
printf("显示里面:ps->delay = %d\n", ps->delay);
//这个函数看了手册也不大理解
sws_scale(ps->psws_ctx, (uint8_t const *const *)pframe->data,
pframe->linesize, 0, ps->pixel_h,
ps->out_frame.data, ps->out_frame.linesize);
ps->sdl_rect.w = ps->window_w;
ps->sdl_rect.h = ps->window_h;
SDL_UpdateTexture(ps->ptexture, NULL,
ps->out_frame.data[0], ps->out_frame.linesize[0]);
SDL_RenderClear(ps->prenderer);
SDL_RenderCopy(ps->prenderer, ps->ptexture, NULL, &ps->sdl_rect);
SDL_RenderPresent(ps->prenderer);
av_frame_free(&pframe);
return 0;
}
/*======================================================================\
* Author (作者): i.sshe
* Date (日期): 2016/10/08
* Others (其他): 获取延迟时间
\*=======================================================================*/
double get_delay(PlayerState *ps)
{
double ret_delay = 0.0;
double frame_delay = 0.0;
double cur_audio_clock = 0.0;
double compare = 0.0;
double threshold = 0.0;
//这里的delay是秒为单位, 化为毫秒:*1000
frame_delay = ps->cur_frame_pts - ps->pre_frame_pts;
if (frame_delay <= 0 || frame_delay >= 1.0)
{
frame_delay = ps->pre_cur_frame_delay;
}
//两帧之间的延时
ps->pre_cur_frame_delay = frame_delay;
ps->pre_frame_pts = ps->cur_frame_pts;
cur_audio_clock = get_audio_clock(ps);
//compare < 0 说明慢了, > 0说明快了
compare = ps->cur_frame_pts - cur_audio_clock;
//设置一个阀值, 是一个正数
//这里设阀值为两帧之间的延迟,
threshold = frame_delay;
//SYNC_THRESHOLD ? frame_delay : SYNC_THRESHOLD;
if (compare <= -threshold) //慢, 加快速度
{
ret_delay = frame_delay / 2;
}
else if (compare >= threshold) //快了,就在上一帧延时的基础上加长延时
{
ret
没有合适的资源?快使用搜索试试~ 我知道了~
ffmepg+SDL2实现的视频播放器
共15个文件
c:5个
h:5个
ts:1个
5星 · 超过95%的资源 需积分: 35 247 下载量 85 浏览量
2016-10-09
00:42:09
上传
评论 9
收藏 5.22MB ZIP 举报
温馨提示
博文:http://blog.csdn.net/i_scream_/article/details/52760033 中的代码。实现了音视频的同步,使用的方法是视频同步音频。
资源推荐
资源详情
资源评论
收起资源包目录
player_v1.5.zip (15个子文件)
video.h 6KB
wrap_base.c 3KB
player.h 6KB
packet_queue.h 4KB
video.c 10KB
结构图.png 26KB
wrap_base.h 3KB
Makefile 563B
audio.h 4KB
packet_queue.c 4KB
naxienian.mp4 1.44MB
结构图.mdj 38KB
player_v1.5.c 6KB
sintel.ts 4.07MB
audio.c 7KB
共 15 条
- 1
i丶scream
- 粉丝: 61
- 资源: 18
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- TG-2024-04-26-183849310.mp4
- 汇编语言的概要介绍与分析
- 个人博客系统设计与开发.zip
- 2023-04-06-项目笔记 - 第一百十五阶段 - 4.4.2.113全局变量的作用域-113 -2024.04.26
- 2023-04-06-项目笔记 - 第一百十五阶段 - 4.4.2.113全局变量的作用域-113 -2024.04.26
- htmlzwbjq_downyi.com.zip
- 无头单向非循环链表的实现(Test.c)
- 无头单向非循环链表的实现(SList.c)
- 浏览器重定向插件更新文件
- SSA-BP麻雀算法优化BP神经网络多特征分类预测(Matlab实现完整源码和数据)
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
- 1
- 2
前往页