目录
一、视频点播系统中视频帧的定位
在视频点播系统中,通过时间戳定位播放的视频帧主要依赖于视频流的编码和解码过程,以及相应的媒体播放框架或库。大致的步骤和概念说明如下:
(一)时间戳的生成
在视频编码过程中,每一帧视频都会被赋予一个时间戳(Timestamp)。这个时间戳通常表示该帧在视频序列中的相对时间位置。对于视频流来说,这个时间戳是连续的,并且以一定的时间间隔递增。
(二)视频流的传输:
当视频流被传输到客户端(如用户的手机或电脑)时,这些时间戳信息会被保留。客户端的媒体播放框架或库会使用这些时间戳来确定如何按顺序播放视频帧。
(三)定位视频帧
当用户想要通过时间戳定位到某个特定的视频帧时,媒体播放框架或库会首先解析这个时间戳,并计算出该时间戳在视频流中对应的位置。然后,它会从这个位置开始解码和播放视频帧,直到达到用户指定的时间戳位置。
二、代码和解释
(一)代码和注释
直接出代码(含注释),如下:
/***********************************************************************
函数:GetVideoFrmNumByTime
参数:
// iSeconds: 查询的时间戳(秒)
// pRealTime: 指向长整型变量的指针,用于存储实际查询的时间(秒)
***********************************************************************/
int CMfsFile::GetVideoFrmNumByTime(long iSeconds, long *pRealTime)
{
// 获取指定时间戳对应的帧编号
// 点播的总时间
long mfstotaltime = m_FileEndParam.FileTime - m_FileStartParam.FileTime;
// 打印调试信息,包括总时间、当前文件项的大小和查询的时间戳
DBGPrint("%s:GetVideoFrmNumByTime Start! mfstotaltime:%ld m_mfsitems.size:%d, iSeconds:%ld", __FUNCTION__, mfstotaltime, m_mfsitems.size(), iSeconds);
// 计算时间戳与文件开始时间之间的偏移量
long offsettime = iSeconds - m_FileStartParam.FileSecondNo;
// 如果偏移量超过总时间,表示查询的时间戳超出了文件的时间范围
if (offsettime > mfstotaltime)
{
// 锁定互斥量,设置文件结束标志,解锁互斥量,打印错误信息,返回-1
m_FileMutex.Lock();
bGetFileEnd = true;
m_FileMutex.Unlock();
DBGPrint("%s: iSeconds:%ld, offsettime:%ld over mfstotaltime:%ld, search file end, over this vod!", __FUNCTION__, iSeconds, offsettime, mfstotaltime);
return -1;
}
// 初始化实际时间为-1
*pRealTime = -1;
// 定义文件编号和时间变量
unsigned int fileno = 0;
long fileno_begintime = 0; // 检索文件的开始时间
long fileno_endtime = 0; //
// 如果文件项列表为空,打印错误信息,返回-1
if(m_mfsitems.size() <= 0)
{
DBGPrint( "%s: avi items is zero!", __FUNCTION__);
return -1;
}
// 获取文件的开始时间
long file_begintime = m_mfsitems[0].begintime;
// 计算跳转的时间,即文件开始时间加上查询的时间戳
long search_time = file_begintime + iSeconds;
// 遍历文件项列表
for (fileno = 0; fileno < m_mfsitems.size(); fileno++)
{
// 获取当前文件项的开始时间和结束时间
fileno_begintime = m_mfsitems[fileno].begintime;
fileno_endtime = m_mfsitems[fileno].endtime;
/************
代码较多,这里适当省略掉
*************/
// 如果查询时间在当前文件项的时间范围内,更新实际时间,跳出循环
if ((search_time >= fileno_begintime) && (search_time <= fileno_endtime))
{
*pRealTime = search_time - file_begintime;
break;
}
}
// 如果遍历结束后还没有找到对应的时间,打印错误信息,返回-1
if(fileno >= m_mfsitems.size())
{
m_FileMutex.Lock();
bGetFileEnd = true;
m_FileMutex.Unlock();
DBGPrint( "%s: fileno:%d over limit m_mfsitems.size:%d by iSeconds:%ld, search file end, over this vod!", __FUNCTION__, fileno, m_mfsitems.size(), iSeconds);
return -1;
}
// 锁定互斥量
m_FileMutex.Lock();
/************
代码较多,这里适当省略掉
*************/
// 更新当前文件编号和本地时间编号
m_iCurFileNo = fileno;
m_ilocalsecondno = ilocalsecondno;
// 打印调试信息,包括查询的时间戳、当前文件编号和本地时间编号
DBGPrint("%s:GetVideoFrmNumByTime End! iSeconds:%ld m_iCurFileNo:%d m_ilocalsecondno:%d!", __FUNCTION__, iSeconds, m_iCurFileNo, m_ilocalsecondno);
// 解锁互斥量
m_FileMutex.Unlock();
// 返回0
return 0;
}
(二)代码解释
1、概述
这段C++代码定义了一个名为`CMfsFile`的类成员函数`GetVideoFrmNumByTime`,该函数的目的是根据给定的时间戳`iSeconds`获取对应的帧编号。如果成功,它返回帧编号;如果失败,它返回-1。
这个函数是视频点播系统的一部分,用于在视频文件中根据时间戳查找对应的帧。
2、详细解释
以下是对代码的详细解释:
(1). 函数`GetVideoFrmNumByTime`开始,它接受两个参数:`iSeconds`(查询的时间戳)和`pRealTime`(指向长整型变量的指针,用于存储实际查询的时间)。
(2). 定义了点播视频的总时间`mfstotaltime`,它是文件结束时间`m_FileEndParam.FileTime`减去文件开始时间`m_FileStartParam.FileTime`。
(3). 调用`DBGPrint`函数,打印函数开始执行的信息,包括总时间、当前文件项的大小和查询的时间戳。
(4). 计算时间戳与文件开始时间之间的偏移量`offsettime`。
(5). 如果`offsettime`大于总时间`mfstotaltime`,表示查询的时间戳超出了文件的时间范围。此时,锁定一个互斥量`m_FileMutex`,设置一个标志`bGetFileEnd`为`true`,表示文件结束,然后解锁互斥量,并打印错误信息,返回-1。
这部分代码如下:
if (offsettime > mfstotaltime)
{
// 锁定互斥量,设置文件结束标志,解锁互斥量,打印错误信息,返回-1
m_FileMutex.Lock();
//设置标志`bGetFileEnd`为`true`,表示文件结束
bGetFileEnd = true;
//解锁互斥量
m_FileMutex.Unlock();
DBGPrint("%s: iSeconds:%ld, offsettime:%ld over mfstotaltime:%ld, search file end, over this vod!", __FUNCTION__, iSeconds, offsettime, mfstotaltime);
return -1;
}
(6). 初始化`pRealTime`为-1,表示未找到时间戳对应的真实时间。
(7). 定义了两个变量`fileno_begintime`和`fileno_endtime`,用于存储文件项的开始和结束时间。
(8). 如果文件项列表`m_mfsitems`的值小于或等于0,表示列表为空,打印错误信息,返回-1。如下所示:
if(m_mfsitems.size() <= 0)
{
DBGPrint( "%s: avi items is zero!", __FUNCTION__);
return -1;
}
(9). 定义了文件的开始时间`file_begintime`,查询时间戳与文件开始时间之和`search_time`。
(11). 在每次循环中,计算当前文件项的开始时间`fileno_begintime`和结束时间`fileno_endtime`。
(12). 解除互斥量的锁定。
(13). 如果成功加载了索引,则设置文件的方向`m_bFileDirection`为`false`(默认是正向加载文件),更新当前文件编号`m_iCurFileNo`和当前秒数`m_ilocalsecondno`。
(14). 打印函数执行结束的信息,包括查询的时间戳、当前文件编号和当前秒数。
(15). 函数结束:返回0,表示成功。
3、总结
这个函数的主要作用是在视频文件中根据给定的时间戳查找对应的帧编号。
(1)它首先检查查询的时间戳是否在文件的播放范围内,
(2)然后遍历文件项列表,找到对应的时间戳,并返回实际的时间和帧编号。
(3)如果在查找过程中遇到任何错误,它将返回-1。
文章正下方可以看到我的联系方式:鼠标“点击” 下面的 “威迪斯特-就是video system 微信名片”字样,就会出现我的二维码,欢迎沟通探讨。