项目最近需要实现播放视频功能,这个在上家公司就做过。虽然跟之前的场景不一样,有以前的功底还是很快可以解决,事实也确实如此。在使用DShow处理完视频分割与合并后,继续使用DShow显示视频,很快即完成。然而在播放dvr录制的视频文件时,发现播放帧率不对,分析发现是dvr存储的视频文件不是按标准格式进行存储(使用ffplay效果还好点,media player根本没法播放),于是重写代码。

先简要说明一下项目:client是delphi开发的GUI程序,视频所有操作功能都由mfc dll实现,这个dll也就是由我实现。delphi只传入要显示视频的窗口句柄、操作类型、文件名,这个跟我在以前设计但未能完工的显示流媒体库有不少借鉴作用,因此在此记录一下。

使用ffmpeg一直到读取文件每一帧、解码,剩下就是显示的工作:解码每一帧的rgb数据在CDC上显示,显示过程中一开始通过CreateDIBSection创建一个HBITMAP对象,memorydc中选入,然后在显示cdc中StretchBlt,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bmpInfoHdr.biPlanes = 1;
bmpInfoHdr.biBitCount = 24;
bmpInfoHdr.biWidth = pAvCdcCtx->width;
bmpInfoHdr.biHeight = pAvCdcCtx->height;
bmpInfoHdr.biSizeImage = nBytes;
bmpInfoHdr.biSize = sizeof(bmpInfoHdr);
 
//创建DIB HBITMAP
hBmpShow = CreateDIBSection(NULL, (BITMAPINFO*)&bmpInfoHdr, DIB_RGB_COLORS, (void**)&pRgbData, NULL, 0);
if (!hBmpShow) {
    itrace("CreateDIBSection failed %d", GetLastError());
    continue;
}
memcpy(pRgbData, pBmpRgbData, nBytes);
 
//显示图片
hBmpBackup = (HBITMAP)m_memDc.SelectObject(hBmpShow);
m_pShowDc->StretchBlt(0, 0, m_width, m_height, &m_memDc, 0, 0,
        pAvCdcCtx->width, pAvCdcCtx->height, SRCCOPY);

结果发现现实视频效果极差,转而研究ffplay代码,发现ffplay分读线程与解码线程。怀疑是播放前未能读取足够的视频帧进行缓存,导致视频在解码播放过程中出现因读取视频占用时间导致效果极差的原因。于是在代码中添加了读/解码线程,修改后发现播放效果没有任何改善。于是排除帧缓冲导致播放问题,这时候看到了yuv viewer代码,发现其显示是通过StretchDIBits实现,且不需要通过CreateDIBSection创建HBITMAP对象。尝试修改代码,播放效果非常好,代码如下

1
2
3
4
m_pShowDc->SetStretchBltMode(STRETCH_DELETESCANS);
StretchDIBits(m_pShowDc->m_hDC, 0, 0, m_width, m_height,
        0, 0, pAvCdcCtx->width, pAvCdcCtx->height,
        pBmpRgbData, (BITMAPINFO*)&bmpInfoHdr, DIB_RGB_COLORS, SRCCOPY);

====视频定位

可以通过前进或者后退多少秒以及百分比对视频进行定位,其实都是获取其绝对时间通过av_rescale_q转成ffmpeg所需要的时间格式,进行视频定位。

我们知道可以通过av_q2d(m_pAvFmtCtx->streams[i]->time_base)* pAvFrame->best_effort_timestamp来获取当前播放时间

1
2
3
AVRational bp = {1, AV_TIME_BASE};
target_pos = av_rescale_q(target_pos, bp, m_pAvFmtCtx->streams[idx]->time_base);
av_seek_frame(m_pAvFmtCtx, idx, target_pos, AVSEEK_FLAG_ANY);

ffmpeg显示视频的更多相关文章

  1. ffmpeg为视频添加时间戳 - 手动编译ffmpeg

    FFMPEG给视频加时间戳水印 项目中需要给视频添加时间戳,理所当然最好用的办法是ffmpeg.在找到正确的做法前,还被网上的答案timecode给水了一下(水的不轻,在这里转了2天),大概是这样写的 ...

  2. 利用FFmpeg生成视频缩略图 2.1.6

    利用FFmpeg生成视频缩略图 1.下载FFmpeg文件包,解压包里的\bin\下的文件解压到 D:\ffmpeg\ 目录下. 下载地址 http://ffmpeg.zeranoe.com/build ...

  3. 使用ffmpeg 对视频截图,和视频转换格式

    //执行CMD命令方法 public static void CmdProcess(string command)//调用CMD        {            //实例化一个进程类      ...

  4. NET 2.0(C#)调用ffmpeg处理视频的方法

    另外:ffmpeg的net封装库 http://www.intuitive.sk/fflib/ NET 2.0 调用FFMPEG,并异步读取输出信息的代码...public void ConvertV ...

  5. 使用FFMPeg对视频进行处理

    FFMPeg处理视频的核心操作方式是命令,无论是在Windows上还是Linux上.那么下边就简单介绍下,常见的处理命令. 示例1:截取一张352×240尺寸大小的,格式为jpg的图片: ffmpeg ...

  6. Java Web 中使用ffmpeg实现视频转码、视频截图

    Java Web 中使用ffmpeg实现视频转码.视频截图 转载自:[ http://www.cnblogs.com/dennisit/archive/2013/02/16/2913287.html  ...

  7. php使用ffmpeg向视频中添加文字字幕

    这篇文章主要介绍了PHP使用ffmpeg给视频增加字幕显示的方法,实例分析了php操作ffmpeg给视频增加字母的技巧,具有一定参考借鉴价值,需要的朋友可以参考下. 本文实例讲述了PHP使用ffmpe ...

  8. (原)使用ass字幕文件通过ffmpeg给视频添加字幕的一些研究

    使用ass字幕文件通过ffmpeg给视频添加字幕的一些研究 Author:lihaiping1603@aliyun.com Create:2019-09-04 最近对ffmpeg给视频文件添加字幕效果 ...

  9. OpenCV-Python 读取显示视频 | 六

    目标 学习读取视频,显示视频和保存视频. 学习从相机捕捉并显示它. 你将学习以下功能:cv.VideoCapture(),cv.VideoWriter() 从相机中读取视频 通常情况下,我们必须用摄像 ...

随机推荐

  1. soft particles

    http://developer.download.nvidia.com/whitepapers/2007/SDK10/SoftParticles_hi.pdf nvdia ------------- ...

  2. 多线程Java Socket编程示例(转)

    这篇做为学习孙卫琴<<Java网络编程精解>>的学习笔记吧.其中采用Java 5的ExecutorService来进行线程池的方式实现多线程,模拟客户端多用户向同一服务器端发送 ...

  3. Windows ftp 连不上Linux

    1.首先检查vsftpd服务器 是否安装 $ rpm -qa | grep vsftpdvsftpd-2.2.2-11.el6.x86_64 2.显示已安装,restart the vsftpd ¥ ...

  4. Unity3D WP8发布解决方案名 DefaultPackageName 修改问题

    原地址:http://blog.csdn.net/w337198302/article/details/16960661 在对Unity3D游戏进行Windows phone 8 发布的时候,首先是需 ...

  5. Javascript表格中搜索

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  6. Android面试题基础(转)

    71道经典Android面试题和答案 1.下列哪些语句关于内存回收的说明是正确的? (b ) A. 程序员必须创建一个线程来释放内存 B.内存回收程序负责释放无用内存 C.内存回收程序允许程序员直接释 ...

  7. 无法解析指定的连接标识符 oracle错误12154

    导出的时候老是报这个错,exp userid=c##yh/yh@MyOracle tables=(stu3) file=d:\e.dmp; 解决了好久,最后都失败了,后来加了127.0.0.1:152 ...

  8. Web中的监听器【Listener】

    Servlet监听器:Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext.HttpSession和ServletRequest等域对象的创建与销毁事件,以及 ...

  9. Shell脚本的编写

    筛选后统计总数 cat logs | grep IconsendRedirect | wc -l >> bb.log 筛选后分类统计并且排序 cat logs | grep Iconsen ...

  10. C#调用Win32 api学习总结

    从.NET平台调用Win32 API Win32 API可以直接控制Microsoft Windows的核心,因为API(Application Programming Interface)本来就是微 ...