当前位置: 首页 > news >正文

企业网站建设兴田德润地址城乡与建设厅网站

企业网站建设兴田德润地址,城乡与建设厅网站,排名优化公司哪家好,创建游戏网站FFmpeg入门:最简单的视频播放器 FFmpeg入门第一篇,制作一个简单的MP4视频播放器。 整体流程 话不多说,直接上流程图 视频播放速率控制 这里可以直接看图中的帧率同步模块,可以分为如下几步 获取到当前帧的预期播放时间&…

FFmpeg入门:最简单的视频播放器

FFmpeg入门第一篇,制作一个简单的MP4视频播放器。

整体流程

话不多说,直接上流程图在这里插入图片描述

视频播放速率控制

这里可以直接看图中的帧率同步模块,可以分为如下几步

  1. 获取到当前帧的预期播放时间:根据时间基time_base和帧pts计算;time_base*pts
  2. 解码渲染过程中,获取当前时间av_gettime,计算和预期播放时间的时间差
  3. 使用SDL_Delay函数延迟播放时间差。

源代码

tutorial01.h

//
//  tutorial02.h
//  tutorial02
//
//  Created by chenhuaiyi on 2025/2/13.
//#ifndef tutorial02_h
#define tutorial02_h#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <libavutil/time.h>#include <SDL.h>
#include <SDL_thread.h>#include <stdio.h>/**宏定义*/
#define SFM_REFRESH_EVENT (SDL_USEREVENT+1)/**全局变量*/
extern int            thread_exit;/**方法声明*/
char* get_frame_type(AVFrame* frame);#endif /* tutorial02_h */

tutorial02.c

// tutorial02.c
// A pedagogical video player that will stream through every video frame as fast as it can.#ifdef __MINGW32__
#undef main /* Prevents SDL from overriding main() */
#endif#include "tutorial02.h"// 控制程序是否结束
int		thread_exit=0;/**获取帧类型*/
char* get_frame_type(AVFrame* frame) {switch (frame->pict_type) {case AV_PICTURE_TYPE_I:return "I";break;case AV_PICTURE_TYPE_P:return "P";break;case AV_PICTURE_TYPE_B:return "B";break;case AV_PICTURE_TYPE_S:return "S";break;case AV_PICTURE_TYPE_SI:return "SI";break;case AV_PICTURE_TYPE_SP:return "SP";break;case AV_PICTURE_TYPE_BI:return "BI";break;default:return "N";break;}
}int main(int argc, char *argv[]) {AVFormatContext*  pFormatCtx = NULL;int               i, videoStream;AVCodecContext*   pCodecCtx = avcodec_alloc_context3(NULL);;AVCodecParameters*  pCodecParam = NULL;const AVCodec*    pCodec = NULL;AVFrame*          pFrame = NULL;AVFrame*          pFrame2 = NULL;AVPacket          packet;AVDictionary*     optionsDict = NULL;struct SwsContext*  sws_ctx = NULL;SDL_Window*       window = NULL;SDL_Renderer*     renderer = NULL;SDL_Texture*      texture=NULL;SDL_Rect          rect;SDL_Event         event;if(argc < 2) {fprintf(stderr, "Usage: test <file>\n");exit(1);}// SDL组件创建if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());exit(1);}// 1. 打开视频文件,获取格式上下文if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)return -1; // Couldn't open file// 2. 对文件探测流信息if(avformat_find_stream_info(pFormatCtx, NULL)<0)return -1; // Couldn't find stream information// 打印信息av_dump_format(pFormatCtx, 0, argv[1], 0);// 3.找到对应的视频流videoStream=-1;for(i=0; i<pFormatCtx->nb_streams; i++)if(pFormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO) {videoStream=i;break;}if(videoStream==-1){return -1; // Didn't find a video stream}// 4. 将视频流编码参数写入上下文pCodecParam = pFormatCtx->streams[videoStream]->codecpar;avcodec_parameters_to_context(pCodecCtx, pCodecParam);// 5. 查找流的编码器pCodec=avcodec_find_decoder(pCodecCtx->codec_id);if(pCodec==NULL) {fprintf(stderr, "Unsupported codec!\n");return -1; // Codec not found}// 6. 打开流的编解码器if(avcodec_open2(pCodecCtx, pCodec, &optionsDict)<0)return -1; // Could not open codec// 7.申请缩放颜色空间格式的上下文sws_ctx =sws_getContext(pCodecCtx->width,pCodecCtx->height,pCodecCtx->pix_fmt,pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_YUV420P,SWS_BILINEAR,NULL,NULL,NULL);// 8.帧分配pFrame=av_frame_alloc();pFrame2=av_frame_alloc();// 9.计算并分配frame帧所占内存空间int numBytes=av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);uint8_t* buffer=(uint8_t*)av_malloc(numBytes*sizeof(uint8_t));av_image_fill_arrays(pFrame2->data, pFrame2->linesize, buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);i=0;Uint32 start_time = SDL_GetTicks();// SDL2的最新创建和渲染窗口方式window = SDL_CreateWindow("SDL2 window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, pCodecCtx->width, pCodecCtx->height, SDL_WINDOW_SHOWN);if (!window) {printf("SDL_CreateWindow Error: %s\n", SDL_GetError());SDL_Quit();return 1;}renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);if (!renderer) {printf("SDL_CreateRenderer Error: %s\n", SDL_GetError());SDL_DestroyWindow(window);SDL_Quit();return 1;}texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);AVRational time_base = pFormatCtx->streams[videoStream]->time_base;int64_t av_start_time = av_gettime();								// 播放开始时间int64_t frame_delay = av_q2d(time_base) * AV_TIME_BASE;				// pts单位(ms*1000)int64_t frame_start_time = av_gettime();// 循环一:对文件上下文持续读取packetwhile(av_read_frame(pFormatCtx, &packet)>=0) {if(packet.stream_index==videoStream) {// 将packet写入编解码器int ret = avcodec_send_packet(pCodecCtx, &packet);if (ret < 0) {printf("packet resolve error!");break;}// 循环二:从解码器中不断读取帧while(!avcodec_receive_frame(pCodecCtx, pFrame)) { // 解码得到数据frame// 帧格式转化,转为YUV420Psws_scale(sws_ctx,(uint8_t const * const *)pFrame->data,pFrame->linesize,0,pCodecCtx->height,pFrame2->data,pFrame2->linesize);// 将AVFrame的数据写入到texture中,然后渲染后windows上rect.x = 0;rect.y = 0;rect.w = pCodecCtx->width;rect.h = pCodecCtx->height;// 更新纹理SDL_UpdateYUVTexture(texture, &rect,pFrame2->data[0], pFrame2->linesize[0],	// 	YpFrame2->data[1], pFrame2->linesize[1],	// 	UpFrame2->data[2], pFrame2->linesize[2]);	//  V// 渲染页面SDL_RenderClear(renderer);SDL_RenderCopy(renderer, texture, NULL, NULL);SDL_RenderPresent(renderer);int64_t pts = pFrame->pts;											// ptsint64_t actual_playback_time = av_start_time + pts * frame_delay;	// 实际播放时间int64_t current_time = av_gettime();if (actual_playback_time > current_time) {SDL_Delay((Uint32)(actual_playback_time-current_time)/1000);	// 延迟当前时间和实际播放时间}i++;printf("第%i帧 | 属于%s | pts为%d | 时长为%.2fms | 实际播放点为%.2fs | 预期播放点为%.2fs\n ",i,get_frame_type(pFrame),(int)pFrame->pts,(double)(av_gettime() - frame_start_time)/1000,(double)(av_gettime() - av_start_time)/AV_TIME_BASE,pFrame->pts * av_q2d(time_base));frame_start_time = av_gettime();}}// Free the packet that was allocated by av_read_frameav_packet_unref(&packet);SDL_PollEvent(&event);switch(event.type) {case SDL_QUIT:SDL_Quit();exit(0);break;default:break;}}Uint32 endTime = SDL_GetTicks();/**打印一些关键参数*/printf("格式: %s\n", pFormatCtx->iformat->name);printf("时长: %lld us\n", pFormatCtx->duration);printf("编码器: %s (%s)\n", pCodec->name, avcodec_get_name(pCodecCtx->codec_id));printf("分辨率: %dx%d\n", pCodecCtx->width, pCodecCtx->height);printf("帧率: %.2f\n", av_q2d(pFormatCtx->streams[videoStream]->avg_frame_rate));printf("帧数: %lld\n", pFormatCtx->streams[videoStream]->nb_frames);printf("比特率: %lld\n", pFormatCtx->bit_rate);printf("pts单位(ms*1000): %.2f\n", av_q2d(pFormatCtx->streams[videoStream]->time_base) * AV_TIME_BASE);printf("视频持续时长为 %d,视频帧总数为 %d\n", (endTime-start_time)/1000, i);// Free the YUV frameav_free(pFrame);av_free(pFrame2);// Close the codec paramavcodec_parameters_free(&pCodecParam);// Close the codecavcodec_free_context(&pCodecCtx);// Close the video fileavformat_close_input(&pFormatCtx);return 0;
}

文章最后,感谢音视频领域的大神@雷霄骅,雷神永垂不朽!!!

http://www.yayakq.cn/news/442790/

相关文章:

  • 怎么在网站添加关键词aso优化平台有哪些
  • 站牛网一键优化软件
  • 阿里国际站韩语网站怎么做安米网在线app制作
  • 网站网站开发的垂直网站导航是谁做的
  • 名师工作室网站建设 意义html手机版网站
  • 上海全上海全国网站建设网站建设选择什么模式
  • 企业建站为什么选择网站定制php做的网站预览
  • 微信公众号链接网站怎么做wordpress改回旧版编辑器
  • 什么是开放式的网站深圳市网站首页
  • 做网站赔钱了互动平台抽手机
  • 做传销网站的html官方网站项目
  • 网站建设招标模板风中有朵雨做的云网站观看
  • 中国个人优秀网站手机网页素材
  • 甘肃系统建站怎么用安钢贴吧
  • 怀化网站定制做的系统怎么和网站对接
  • 江西建网站做优化珠海网络营销外包收费情况
  • 设计常去的网站合肥房地产最新消息
  • 义乌网站建设公司价位洛阳seo网站
  • cps推广是什么意思简述seo的概念
  • 淘宝做链接的网站网站的外部链接怎么做
  • 宝安做棋牌网站建设找哪家效益快网页设计模板加代码
  • 12306网站开发时间软件商城推荐
  • 网站站长在哪登陆后台义乌正规自适应网站建设首选
  • 中山网站制作系统建设人行官方网站下载
  • 电商网站建设的目标企业网站的模式
  • 站长工具查询网站兰州网站建设索王道下拉
  • 自学网站建设需要什么学历wordpress安装到子目录下
  • 怎样在设计网站做图赚钱吗六安市城乡建设网站
  • 电商运营 网站运营建设九九网站
  • 个人如果做网站赚钱吗网站建设公司权威机构