源代码 播放

由于FFmpeg的不断更新,为了深入理解FFmpeg,我参照雷神的代码结构图,重新画了一张图。

主要参考的FFmpeg官方代码:FFmpeg: fftools/ffplay.c File Reference

FFmpeg 版本:3.4.9 released on 2021-10-1

源代码结构图

源代码 播放

注:

  1. 在event_loop函数中判断用户输入(键盘、鼠标等),用户输入有很多种,此结构图没有全部画出来。
  2. 此结构图忽略了字幕的处理(打开、读入、解码、显示、关闭)

C++音视频开发学习地址:【免费】FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发-学习视频教程-腾讯课堂

代码逻辑

源代码 播放

播放模式分析

在音视频播放时有不同的模式:

enum ShowMode { SHOW_MODE_NONE = -1, SHOW_MODE_VIDEO = 0, // 播放视频画面 SHOW_MODE_WAVES, // 不显示视频画面,只显示波点 SHOW_MODE_RDFT, // 不显示视频画面,只黑屏 SHOW_MODE_NB } show_mode;

C++音视频开发学习资料:点击领取→音视频开发(资料文档+视频教程+面试题)(FFmpeg+WebRTC+RTMP+RTSP+HLS+RTP)

源代码 播放

SHOW_MODE_VIDEO

播放画面正常

对应播放的代码:

static void video_image_display(VideoState *is) { Frame *vp; Frame *sp = NULL; SDL_Rect rect; vp = frame_queue_peek_last(&is->pictq); /*...process code for subtitile...*/ calculate_display_rect(&rect, is->xleft, is->ytop, is->width, is->height, vp->width, vp->height, vp->sar); if (!vp->uploaded) { if (upload_texture(&is->vid_texture, vp->frame, &is->img_convert_ctx) < 0) return; vp->uploaded = 1; vp->flip_v = vp->frame->linesize < 0; } SDL_RenderCopyEx(renderer, is->vid_texture, NULL, &rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0); /*...show subtitile code...*/ }

SHOW_MODE_WAVES

播放画面

源代码 播放

此画面是由video_audio_display函数生成的。

对应播放的代码:

static void video_audio_display(VideoState *s) { int i, i_start, x, y1, y, ys, delay, n, nb_display_channels; int ch, channels, h, h2; int64_t time_diff; int rdft_bits, nb_freq; for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++) ; nb_freq = 1 << (rdft_bits - 1); /* compute display index : center on currently output samples */ channels = s->audio_tgt.channels; nb_display_channels = channels; if (!s->paused) { int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq); n = 2 * channels; delay = s->audio_write_buf_size; delay /= n; /* to be more precise, we take into account the time spent since the last buffer computation */ if (audio_callback_time) { time_diff = av_gettime_relative() - audio_callback_time; delay -= (time_diff * s->audio_tgt.freq) / 1000000; } delay += 2 * data_used; if (delay < data_used) delay = data_used; i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE); if (s->show_mode == SHOW_MODE_WAVES) { h = INT_MIN; for (i = 0; i < 1000; i += channels) { int idx = (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE; int a = s->sample_array; int b = s->sample_array[(idx + 4 * channels) % SAMPLE_ARRAY_SIZE]; int c = s->sample_array[(idx + 5 * channels) % SAMPLE_ARRAY_SIZE]; int d = s->sample_array[(idx + 9 * channels) % SAMPLE_ARRAY_SIZE]; int score = a - d; if (h < score && (b ^ c) < 0) { h = score; i_start = idx; } } } s->last_i_start = i_start; } else { i_start = s->last_i_start; } if (s->show_mode == SHOW_MODE_WAVES) { SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); /* total height for one channel */ h = s->height / nb_display_channels; /* graph height / 2 */ h2 = (h * 9) / 20; for (ch = 0; ch < nb_display_channels; ch++) { i = i_start + ch; y1 = s->ytop + ch * h + (h / 2); /* position of center line */ for (x = 0; x < s->width; x++) { y = (s->sample_array * h2) >> 15; if (y < 0) { y = -y; ys = y1 - y; } else { ys = y1; } fill_rectangle(s->xleft + x, ys, 1, y); i += channels; if (i >= SAMPLE_ARRAY_SIZE) i -= SAMPLE_ARRAY_SIZE; } } SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); for (ch = 1; ch < nb_display_channels; ch++) { y = s->ytop + ch * h; fill_rectangle(s->xleft, y, s->width, 1); } } }

SHOW_MODE_RDFT

播放画面

源代码 播放

此画面是由video_audio_display函数生成的。

对应播放的代码:

static void video_audio_display(VideoState *s) { int i, i_start, x, y1, y, ys, delay, n, nb_display_channels; int ch, channels, h, h2; int64_t time_diff; int rdft_bits, nb_freq; for (rdft_bits = 1; (1 << rdft_bits) < 2 * s->height; rdft_bits++) ; nb_freq = 1 << (rdft_bits - 1); /* compute display index : center on currently output samples */ channels = s->audio_tgt.channels; nb_display_channels = channels; if (!s->paused) { int data_used= s->show_mode == SHOW_MODE_WAVES ? s->width : (2*nb_freq); n = 2 * channels; delay = s->audio_write_buf_size; delay /= n; /* to be more precise, we take into account the time spent since the last buffer computation */ if (audio_callback_time) { time_diff = av_gettime_relative() - audio_callback_time; delay -= (time_diff * s->audio_tgt.freq) / 1000000; } delay += 2 * data_used; if (delay < data_used) delay = data_used; i_start= x = compute_mod(s->sample_array_index - delay * channels, SAMPLE_ARRAY_SIZE); if (s->show_mode == SHOW_MODE_WAVES) { h = INT_MIN; for (i = 0; i < 1000; i += channels) { int idx = (SAMPLE_ARRAY_SIZE + x - i) % SAMPLE_ARRAY_SIZE; int a = s->sample_array; int b = s->sample_array[(idx + 4 * channels) % SAMPLE_ARRAY_SIZE]; int c = s->sample_array[(idx + 5 * channels) % SAMPLE_ARRAY_SIZE]; int d = s->sample_array[(idx + 9 * channels) % SAMPLE_ARRAY_SIZE]; int score = a - d; if (h < score && (b ^ c) < 0) { h = score; i_start = idx; } } } s->last_i_start = i_start; } else { i_start = s->last_i_start; } if (s->show_mode == SHOW_MODE_WAVES) { /* process for SHOW_MODE_WAVES*/ } else { if (realloc_texture(&s->vis_texture, SDL_PIXELFORMAT_ARGB8888, s->width, s->height, SDL_BLENDMODE_NONE, 1) < 0) return; nb_display_channels= FFMIN(nb_display_channels, 2); if (rdft_bits != s->rdft_bits) { av_rdft_end(s->rdft); av_free(s->rdft_data); s->rdft = av_rdft_init(rdft_bits, DFT_R2C); s->rdft_bits = rdft_bits; s->rdft_data = av_malloc_array(nb_freq, 4 *sizeof(*s->rdft_data)); } if (!s->rdft || !s->rdft_data){ av_log(NULL, AV_LOG_ERROR, "Failed to allocate buffers for RDFT, switching to waves display\n"); s->show_mode = SHOW_MODE_WAVES; } else { FFTSample *data; SDL_Rect rect = {.x = s->xpos, .y = 0, .w = 1, .h = s->height}; uint32_t *pixels; int pitch; for (ch = 0; ch < nb_display_channels; ch++) { data = s->rdft_data + 2 * nb_freq * ch; i = i_start + ch; for (x = 0; x < 2 * nb_freq; x++) { double w = (x-nb_freq) * (1.0 / nb_freq); data = s->sample_array * (1.0 - w * w); i += channels; if (i >= SAMPLE_ARRAY_SIZE) i -= SAMPLE_ARRAY_SIZE; } av_rdft_calc(s->rdft, data); } /* Least efficient way to do this, we should of course * directly access it but it is more than fast enough. */ if (!SDL_LockTexture(s->vis_texture, &rect, (void **)&pixels, &pitch)) { pitch >>= 2; pixels += pitch * s->height; for (y = 0; y < s->height; y++) { double w = 1 / sqrt(nb_freq); int a = sqrt(w * sqrt(data[2 * y + 0] * data[2 * y + 0] + data[2 * y + 1] * data[2 * y + 1])); int b = (nb_display_channels == 2 ) ? sqrt(w * hypot(data[2 * y + 0], data[2 * y + 1])) : a; a = FFMIN(a, 255); b = FFMIN(b, 255); pixels -= pitch; *pixels = (a << 16) + (b << 8) + ((a+b) >> 1); } SDL_UnlockTexture(s->vis_texture); } SDL_RenderCopy(renderer, s->vis_texture, NULL, NULL); } if (!s->paused) s->xpos++; if (s->xpos >= s->width) s->xpos= s->xleft; } }

本文【源代码 播放】由作者: 前端后端 提供,本站不拥有所有权,只提供储存服务,如有侵权,联系删除!
本文链接:https://www.cuoshuo.com/blog/4477.html

(0)
上一篇 2023-03-14 08:13:14
下一篇 2023-03-14 08:16:56

相关推荐

  • 3d材质库的材质怎么删除 3d如何一键去掉所有的材质

    今天来讲一下3dmax节点材质编辑器。 很多人在学习3DMAX时都是使用精简模式的材质编辑器。精简模式的材质编辑器结构简单,对于初学者来说比较容易掌握 但当我们在实际工作的时候,往往会用到比较复杂的材质制作逻辑,这时候精简模式的材质编辑器就会显得很不方便。 节点式材质编辑器的优点就在于,它能够把整个材质的编辑过程和逻辑关系以及素材的引用,清晰直观的呈现出来。…

    2023-03-20
    000
  • 十六进制转十进制小数点后怎么算(十六进制50如何表示)

    进制的转换 1)R进制转十进制:按权展开 二进制转十进制:10100.01 = 1 x 2^4 + 1 x 2^2 + 1 x 2^-2 七进制转十进制:604.01 = 6 x 7^4 + 4 x 7^0 + 1 x 7^-2 说明:小数点前从0开始,小数点后从-1开始; 多少进制转十进制,则底数替换成多少 2)十进制转R进制:短除法 十进制94转二进制 …

    2023-03-20
    000
  • ccd摄像头和普通摄像头区别

    CMOS与CCD技术自诞生以来,它们的抢位之争自诞生至今就没有停止过。正如您所知道的一样,目前安防监控摄像机的图像传感器基础技术,主要也是CCD和CMOS两种技术。目前市面上的模拟摄像机多是CCD为主,而网络摄像机特别是今年兴起的百万像素级高清网络摄像机,尤以CMOS技术应用居多。 CCD与CMOS传感器是当前被普遍采用的两种图像传感器,两者都是利用感光二极…

    2023-03-20
    100
  • rar文件怎么改为正常文件

    文件本身的压缩包损坏造成压缩文件在解压过程中被损坏,压缩文件已损坏怎么办?您可以通过电脑系统或者软件来恢复压缩的文件。来看看这篇文章,里面有如何解决压缩文件损坏问题的详细步骤。 一、通过压缩包自身修复 想要打开压缩好的文件,发现压缩文件打开显示已被损坏,有什么方法可以修复它吗?可以通过压缩包自身来修复。 演示机型:惠普(HP)战X 系统版本:Windows …

    2023-03-14
    400
  • 某高校学生档案管理系统

    本期主编:星辰:高校档案管理系统有哪些功能? 随着现在的教育水平上涨,各高校的招生人数也在不断地增加,学生的数量也是空前壮大。那么高校的档案工作将会迎来新的挑战。那档案管理难怎么办呢? 别急,科技的创新也为管理工作带来了新型的工具“档案管理系统”,那么系统到底有哪些功能呢?可以帮助我们做到哪些呢?今天就给大家分享一下,记得收藏喔。 往期也分享了关于档案管理的…

    2023-03-20
    000
  • swing是什么舞种

    《爵士萨克斯演奏基础入门》 第二讲:Swing(摇摆)律动基本理论与练习方法 直播:4月1日星期三 14:00 【学习金句】             爵士乐是一种语言 无论儿童 还是老人 都可以学! ——李高阳 第二讲:Swing(摇摆)律动基本理论与练习方法 直播:4月1日星期三 14:00 识别二维码预约报名学习 |编辑:孙铭泽

    2023-03-20
    000
  • 需求分析软件接口和硬件接口_需求分析主要解决软件

    文档说明 一份漂亮的软件需求分析报告,至少包含引言、综合描述、外部接口需求、系统功能需求、其他非功能需求、词汇表、数据定义、分析模型、待定问题列表。下面一一分析每个模块具体的具体内容。 引言 引言部分我们要说明文档编写的目的、项目的风险、文档的一些特殊约定、产品的范围和编写文档的参考文献。 其中编写目的和项目风险是比较重要的两个模块,要详细展开编写,具体编写…

    2023-03-20
    000
  • web标准以及w3c标准是什么_web标准是什么

    万维网联盟(W3C)与 FIDO 联盟近日宣布,Web 认证(Web Authentication,简称 WebAuthn)现已成为正式 Web 标准。 WebAuthn 于2015年11月由 W3C 和 Fido 联盟宣布,现已成为网上无密码登录的开放标准。它由 W3C 贡献者支持,其中包括 Airbnb、阿里巴巴、苹果、谷歌、IBM、英特尔、微软、Moz…

    2023-03-09
    1000
  • swf转gif用什么软件_swf如何转gif

    还想着Excel那个死板的图表吗,改用PS做又太麻烦?Swiff Chart 或许是个不错的选择。 傻瓜式上手 屌炸天效果 Swiff Chart 可以根据输入的数据,或直接导入CSV、XLS、TXT文件中的数据,动态绘制出各种常见的统计图,如:条形统计图、饼形统计图、折线统计图等,最后可将统计图输出为SWF格式(flash格式),而整个过程只需要简单的六步…

    2023-03-20
    000
  • android 直播聊天弹幕

    随着 Android 开发走向成熟,每天都会涌现出各种各样与 Android 相关的开发工具,但是我们每天使用的各类库总是不可或缺的。这里,小编向大家推荐一些目前码云上比较具有创意的 Android 库,希望方便大家能够做出更酷更好玩的产品。 当然,如果你很喜欢以下提到的库,别忘了分享给其他人哦。 1. 项目名称: 智能下拉刷新框架 SmartRefresh…

    2023-03-14
    100

发表回复

登录后才能评论
返回顶部
错说博客上线啦!