ffmpeg中添加音视频解密算法
主要代码
ffmpeg的框架很庞大,这次主要关注点是文件初始数据流的提取传输和解密操作,不涉及音视频解码的具体流程
private_protocol
在IYInitPrivateProtocolGlobalInfo中初始化各种接口
static void IYInitPrivateProtocolGlobalInfo(PRIVATE_PROTOCOL_INFO *pPrivateProtocolInfo)
{
if (!pPrivateProtocolInfo)
{
return;
}
if (gpPrivateProtocolGlobalInfo)
{
gpPrivateProtocolGlobalInfo->sPrivateProtocolInfoList.AddData(pPrivateProtocolInfo);
LOGMSG(DBG_LEVEL_I, "InitPrivateProtocolGlobalInfo, add protocol %x, total count=%d.\n",
pPrivateProtocolInfo,
gpPrivateProtocolGlobalInfo->sPrivateProtocolInfoList.GetCount());
return;
}
gpPrivateProtocolGlobalInfo = new PRIVATE_PROTOCOL_GLOBALINFO;
gpPrivateProtocolGlobalInfo->pDataOperatorDll = NULL;
gpPrivateProtocolGlobalInfo->sPrivateProtocolInfoList.AddData(pPrivateProtocolInfo);
LOGMSG(DBG_LEVEL_I, "InitPrivateProtocolGlobalInfo, add protocol %x, total count=%d.\n",
pPrivateProtocolInfo,
gpPrivateProtocolGlobalInfo->sPrivateProtocolInfoList.GetCount());
InitSysLibCodeConvert();
InitSysLibCURL();
gpPrivateProtocolGlobalInfo->pfnCheckProtocol =CheckFileProtocol;
if (!gpPrivateProtocolGlobalInfo->pfnCheckProtocol)
{
LOGMSG(DBG_LEVEL_I, "protocol %x miss DataOperator_CheckFileProtocol function.\n",pPrivateProtocolInfo);
return;
}
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_Open =
IY_DataOperator_Access_Open;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_Close =
IY_DataOperator_Access_Close;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetBlockSize =
IY_DataOperator_Access_GetBlockSize;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetCacheBlockCount =
IY_DataOperator_Access_GetCacheBlockCount;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetRetainBlockCount =
IY_DataOperator_Access_GetRetainBlockCount;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetFileSize =
IY_DataOperator_Access_GetFileSize;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_ReadBuffer =
IY_DataOperator_Access_ReadBuffer;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_ReadOneBlock =
IY_DataOperator_Access_ReadOneBlock;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_SupportReadRandom =
IY_DataOperator_Access_SupportReadRandom;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_CancelRead =
IY_DataOperator_Access_CancelRead;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_EnableSlowRead =
IY_DataOperator_Access_EnableSlowRead;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetReadSpeedKBPS =
IY_DataOperator_Access_GetReadSpeedKBPS;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sProcessInfo.pfn_SO_P_Init =
IY_DataOperator_Process_Init;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sProcessInfo.pfn_SO_P_Deinit =
IY_DataOperator_Process_Deinit;
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sProcessInfo.pfn_SO_P_BufferPostCallback =
IY_DataOperator_Process_BufferPostCallback;
}
在PRIVATE_PROTOCOL_Open函数中调用
int32_t PRIVATE_PROTOCOL_Open(const char *pszUrl, int eFlag, void **pUrlHandle)
{
LOGMSG(DBG_LEVEL_I, "%s: url=%s, flag=%d", __PRETTY_FUNCTION__, pszUrl, eFlag);
//ALOGD("PRIVATE_PROTOCOL_Open enter");
if (NULL == pszUrl || NULL == pUrlHandle)
{
LOGMSG(DBG_LEVEL_I, "%s: invalid param\n", __PRETTY_FUNCTION__);
return WSD_FAILURE;
}
const char *p = strcasestr(pszUrl, PRIVATE_PROTOCOL);
if (NULL == p)
{
LOGMSG(DBG_LEVEL_I, "%s: not support url\n", __PRETTY_FUNCTION__);
return WSD_FAILURE;
}
p = p + strlen(PRIVATE_PROTOCOL);
LOGMSG(DBG_LEVEL_I, "%s: real url is: %s \n", __PRETTY_FUNCTION__, p);
PRIVATE_PROTOCOL_INFO *pPrivateProtocolInfo = new PRIVATE_PROTOCOL_INFO;
if (NULL == pPrivateProtocolInfo)
{
LOGMSG(DBG_LEVEL_I, "%s: malloc private protocol info fail\n", __PRETTY_FUNCTION__);
return WSD_FAILURE;
}
pPrivateProtocolInfo->sDataStreamReader = new CSTBDataStreamReader();
if (NULL == pPrivateProtocolInfo->sDataStreamReader)
{
LOGMSG(DBG_LEVEL_I, "%s: malloc sDataStreamReader info fail\n", __PRETTY_FUNCTION__);
return WSD_FAILURE;
}
pPrivateProtocolInfo->sDataCatchBuffer = new CDataCacheBuffer();
if (NULL == pPrivateProtocolInfo->sDataCatchBuffer)
{
LOGMSG(DBG_LEVEL_I, "%s: malloc sDataCatchBuffer info fail\n", __PRETTY_FUNCTION__);
return WSD_FAILURE;
}
//调用IYInitPrivateProtocolGlobalInfo
IYInitPrivateProtocolGlobalInfo(pPrivateProtocolInfo);
if (gpPrivateProtocolGlobalInfo)
{
// check if this file is supported
const char* cRemoveProtocolFileName = gpPrivateProtocolGlobalInfo->pfnCheckProtocol(p);
if (cRemoveProtocolFileName)
{
p = cRemoveProtocolFileName;
LOGMSG(DBG_LEVEL_I, "%s: real cFilename is: %s \n", __PRETTY_FUNCTION__, p);
pPrivateProtocolInfo->sDataStreamReader->SetDataOperatorAccessFunction(
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_Open,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_Close,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetBlockSize,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetCacheBlockCount,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetRetainBlockCount,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetFileSize,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_ReadBuffer,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_ReadOneBlock,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_SupportReadRandom,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_CancelRead,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_EnableSlowRead,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sAccessInfo.pfn_SO_A_GetReadSpeedKBPS);
pPrivateProtocolInfo->sDataStreamReader->SetDataOperatorProcessFunction(
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sProcessInfo.pfn_SO_P_Init,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sProcessInfo.pfn_SO_P_Deinit,
gpPrivateProtocolGlobalInfo->sDataOperatorEntry.sProcessInfo.pfn_SO_P_BufferPostCallback);
}
}
if (!pPrivateProtocolInfo->sDataStreamReader->Open(
pPrivateProtocolInfo->sDataCatchBuffer,
"",
p,
FALSE,
0,
""))
{
LOGMSG(DBG_LEVEL_I, "%s: file open fail\n", __PRETTY_FUNCTION__);
DeInitPrivateProtocolGlobalInfo(pPrivateProtocolInfo);
delete pPrivateProtocolInfo->sDataStreamReader;
pPrivateProtocolInfo->sDataStreamReader = NULL;
delete pPrivateProtocolInfo->sDataCatchBuffer;
pPrivateProtocolInfo->sDataCatchBuffer = NULL;
delete pPrivateProtocolInfo;
pPrivateProtocolInfo = NULL;
*pUrlHandle = NULL;
return WSD_FAILURE;
}
else
{
pPrivateProtocolInfo->bHasReadError = FALSE;
pPrivateProtocolInfo->cbArgs.pfnCallback = NULL;
pPrivateProtocolInfo->cbArgs.userdata = NULL;
*pUrlHandle = (void *)pPrivateProtocolInfo;
LOGMSG(DBG_LEVEL_I, "%s: file open success %p\n", __PRETTY_FUNCTION__, pPrivateProtocolInfo);
return WSD_SUCCESS;
}
}
IYDataOperator
IYDataOperator.h
#pragma once
#include "BaseLock.h"
#include "PtrControl.h"
#include "FileOperator.h"
#include "IYDecrypt.h"
#include "OSKVideoDecrypt.h"
#include "HttpFileClient.h"
#include "BasePlayer.h"
#include "dataoperator_def.h"
class IYDataOperator
{
public:
IYDataOperator();
~IYDataOperator();
public:
BOOL Open(
const char* cServerName,
const char* cFileName,
BOOL bIsPreview,
int nOSKDecryptType,
const char* cSTBDecryptOEMID);
void Close();
UINT32 GetBlockSize();
UINT32 GetCacheBlockCount();
UINT32 GetRetainBlockCount();
UINT64 GetFileSize();
size_t ReadBuffer(
UINT64 uFromPos,
BYTE *pBuffer,
size_t nBufLen,
UINT64 uTimeout,
BOOL bUseContinueRead);
UINT32 ReadOneBlock(
BYTE **ppWorkingBuffer,
UINT32 uBlockIndex,
UINT32 uBlockSize,
BOOL bLastBlock,
UINT64 uTimeout,
BOOL bUseContinueRead);
BOOL SupportReadRandom();
void CancelRead();
void EnableSlowRead(
BOOL bEnableSlowRead);
float GetReadSpeedKBPS();
private:
size_t ReadBufferNoDecrypt(
UINT64 uFromPos,
BYTE *pBuffer,
size_t nBufLen,
UINT64 uTimeout,
BOOL bUseContinueRead);
private:
UINT64 mFileSize;
UINT32 mBlockSize;
UINT32 mCacheBlockCount;
UINT32 mRetainBlockCount;
BUFFER_FILE_TYPE mBufferFileType;
int mOSKDecryptType;
BYTE *mpWorkingBuffer;
float mRealTimeReadSpeedKBPS;
private:
CHttpFileClient mHttpFile;
FILE *mpLocalFile;
BOOL mCancelRead;
BOOL mEnableSlowRead;
CIYDecrypt mIYDecrypt;
COSKVideoDecrypt mOSKVideoDecrypt;
BYTE *mpDecryptBuffer;
};
void* IY_DataOperator_Access_Open(
const char* cServerName,
const char* cFileName,
BOOL bIsPreview,
int nDecryptType,
const char* cOEMID);
void IY_DataOperator_Access_Close(
void* pHandle);
UINT32 IY_DataOperator_Access_GetBlockSize(
void* pHandle);
UINT32 IY_DataOperator_Access_GetCacheBlockCount(
void* pHandle);
UINT32 IY_DataOperator_Access_GetRetainBlockCount(
void* pHandle);
UINT64 IY_DataOperator_Access_GetFileSize(
void* pHandle);
ssize_t IY_DataOperator_Access_ReadBuffer(
void* pHandle,
UINT64 uFromPos,
BYTE *pBuffer,
size_t nBufLen,
UINT64 uTimeout,
BOOL bUseContinueRead);
UINT32 IY_DataOperator_Access_ReadOneBlock(
void* pHandle,
BYTE **ppWorkingBuffer,
UINT32 uBlockIndex,
UINT32 uBlockSize,
BOOL bLastBlock,
UINT64 uTimeout,
BOOL bUseContinueRead);
BOOL IY_DataOperator_Access_SupportReadRandom(
void* pHandle);
void IY_DataOperator_Access_CancelRead(
void* pHandle);
void IY_DataOperator_Access_EnableSlowRead(
void* pHandle,
BOOL bEnableSlowRead);
float IY_DataOperator_Access_GetReadSpeedKBPS(
void* pHandle);
void* IY_DataOperator_Process_Init(
void* pHandle);
void IY_DataOperator_Process_Deinit(
void* pHandle,
void *pUserData);
void IY_DataOperator_Process_BufferPostCallback(
void* pHandle,
void *pUserData,
UINT64 uDataPos,
BYTE *pBuffer,
UINT32 nBufLen);
const char* CheckFileProtocol(const char* cFileName);
IYDataOperator.cpp
#include "IYDataOperator.h"
#include <errno.h>
#include <signal.h>
#include "commfunc.h"
#include "DbgOutput.h"
#include "FileOperator.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// read block size 是每次实际read的size,越大则中断read的耗时越大
#define STBSTREAM_HTTP_READ_BLOCKSIZE (32*SIZE_1K)
#define STBSTREAM_NORMAL_READ_BLOCKSIZE (512*SIZE_1K)
// 奥斯卡解密一个 Block 需要 2.5M, 4 个 block,一共10M,
#define DECRYPT_TOTAL_BLOCK_COUNT 4
#ifdef HISI3719C
// 海思3719C在切换原伴唱的时候会往前seek一段,保留部分buffer会加速seek
#define DECRYPT_RETAIN_BLOCK_COUNT 0
#else
#define DECRYPT_RETAIN_BLOCK_COUNT 0
#endif
#define DECRYPT_BLOCK_SIZE (5*512*SIZE_1K)
// 网络版本一个Block 需要 512K, 20 个 block,一共10M,
// 网络版本,一般是buffer越大,在网速越快的环境下优势越明显
// 但如果在低速网络下,buffer越大,可能造成的浪费就越明显
#define HTTP_TOTAL_BLOCK_COUNT 20
#ifdef HISI3719C
// 海思3719C在切换原伴唱的时候会往前seek一段,保留部分buffer会加速seek
#define HTTP_RETAIN_BLOCK_COUNT 0
#else
#define HTTP_RETAIN_BLOCK_COUNT 0
#endif
#define HTTP_BLOCK_SIZE (512*SIZE_1K)
// 本地文件一个Block 需要 512K, 20 个 block,一共10M
#define NORMAL_TOTAL_BLOCK_COUNT 20
#ifdef HISI3719C
// 海思3719C在切换原伴唱的时候会往前seek一段,保留部分buffer会加速seek
#define NORMAL_RETAIN_BLOCK_COUNT 0
#else
#define NORMAL_RETAIN_BLOCK_COUNT 0
#endif
#define NORMAL_BLOCK_SIZE (512*SIZE_1K)
IYDataOperator::IYDataOperator()
{
mBufferFileType = BufferFileType_File;
mCancelRead = FALSE;
mEnableSlowRead = TRUE;
mpLocalFile = NULL;
mRealTimeReadSpeedKBPS = 0.0;
mFileSize = 0;
mBlockSize = 0;
mCacheBlockCount = 0;
mRetainBlockCount = 0;
mOSKDecryptType = 0;
mpWorkingBuffer = NULL;
mpDecryptBuffer = NULL;
}
IYDataOperator::~IYDataOperator()
{
}
BOOL IYDataOperator::Open(
const char* cServerName,
const char* cFileName,
BOOL bIsPreview,
int nOSKDecryptType,
const char* cSTBDecryptOEMID)
{
Close();
LOGMSG(DBG_LEVEL_D, "%s +++\n", __PRETTY_FUNCTION__);
BOOL bOpenOK = FALSE;
mCancelRead = FALSE;
mOSKDecryptType = nOSKDecryptType;
do
{
if ((strncasecmp(cFileName, "http://", 7) == 0)||
(strncasecmp(cFileName, "https://", 8) == 0))
{
if (!mHttpFile.OpenFile(cFileName))
{
LOGMSG(DBG_LEVEL_E, "open http file %s failed\n", cFileName);
break;
}
LOGMSG(DBG_LEVEL_I, "open HttpFile file %s success\n", cFileName);
mFileSize = mHttpFile.GetFileSize();
mBufferFileType = BufferFileType_Http;
mEnableSlowRead = FALSE;
}
else
{
mpLocalFile = fopen(cFileName, "rb");
//LOGMSG(DBG_LEVEL_I, "open local file %s success\n", cFileName);
if (!mpLocalFile)
{
LOGMSG(DBG_LEVEL_E, "open local file %s failed, error=%s\n", cFileName, strerror(errno));
break;
}
fseeko64(mpLocalFile, 0, SEEK_END);
INT64 lFilePos = ftello64(mpLocalFile);
if (lFilePos < 0)
{
mFileSize = 0;
}
else
{
mFileSize = (UINT64)lFilePos;
}
fseeko64(mpLocalFile, 0, SEEK_SET);
mBufferFileType = BufferFileType_File;
mEnableSlowRead = TRUE;
}
if (mFileSize == 0)
{
LOGMSG(DBG_LEVEL_E, "local file %s has no data\n", cFileName);
break;
}
LOGMSG(DBG_LEVEL_D, "%s, mFileSize=%lld\n", __PRETTY_FUNCTION__, mFileSize);
// 检测是否是AES加密
LOGMSG(DBG_LEVEL_D, "%s, Detect Encrypt Type\n", __PRETTY_FUNCTION__);
mIYDecrypt.ResetEncryptType();
mIYDecrypt.DetectLocalFileEncryptType(cFileName, cSTBDecryptOEMID);
if ( mIYDecrypt.GetEncryptType() == IYENCRYPTTYPE_mp36)
{
LOGMSG(DBG_LEVEL_I, "file(%s) is encrypt as IYENCRYPTTYPE_mp36 Encode Type1\n", cFileName);
}
else if ( mIYDecrypt.GetEncryptType() == IYENCRYPTTYPE_li6)
{
LOGMSG(DBG_LEVEL_I, "file(%s) is encrypt as IYENCRYPTTYPE_li6 Encode Type1\n", cFileName);
}
else if ( mIYDecrypt.GetEncryptType() == IYENCRYPTTYPE_ld6)
{
LOGMSG(DBG_LEVEL_I, "file(%s) is encrypt as IYENCRYPTTYPE_ld6 Encode Type1\n", cFileName);
}
else if ( mIYDecrypt.GetEncryptType() == IYENCRYPTTYPE_vk6)
{
LOGMSG(DBG_LEVEL_I, "file(%s) is encrypt as IYENCRYPTTYPE_vk6 Encode Type1\n", cFileName);
}
else if ( mIYDecrypt.GetEncryptType() == IYENCRYPTTYPE_mvh5)
{
LOGMSG(DBG_LEVEL_I, "file(%s) is encrypt as IYENCRYPTTYPE_mvh5 Encode Type1\n", cFileName);
}
else
{
LOGMSG(DBG_LEVEL_I, "%s, Encrypt Type = NONE\n", __PRETTY_FUNCTION__);
}
//OSK解密
if (mOSKDecryptType != 0)
{
char cDecryptName[MAX_PATH];
sprintf(cDecryptName, "//%s/%s", cServerName, cFileName);
char *c = strchr(cDecryptName, ':');
if (c != NULL)
{
*c = '$';
}
mOSKVideoDecrypt.InitDecrypt(cDecryptName, mFileSize, mOSKDecryptType);
mBlockSize = DECRYPT_BLOCK_SIZE;
mCacheBlockCount = DECRYPT_TOTAL_BLOCK_COUNT;
mRetainBlockCount = DECRYPT_RETAIN_BLOCK_COUNT;
}
else
{
mBlockSize = NORMAL_BLOCK_SIZE;
mCacheBlockCount = NORMAL_TOTAL_BLOCK_COUNT;
mRetainBlockCount = NORMAL_RETAIN_BLOCK_COUNT;
}
mpWorkingBuffer = new BYTE[mBlockSize];
mpDecryptBuffer = new BYTE[mBlockSize];
bOpenOK = TRUE;
} while (0);
if (!bOpenOK)
{
Close();
}
LOGMSG(DBG_LEVEL_D, "%s ---\n", __PRETTY_FUNCTION__);
return bOpenOK;
}
void IYDataOperator::Close()
{
LOGMSG(DBG_LEVEL_D, "%s +++\n", __PRETTY_FUNCTION__);
if (mpLocalFile != NULL)
{
fclose(mpLocalFile);
mpLocalFile = NULL;
LOGMSG(DBG_LEVEL_I, "close local file success\n");
}
mHttpFile.CloseFile();
mRealTimeReadSpeedKBPS = 0.0;
mFileSize = 0;
mBlockSize = 0;
SAFE_DELETEARRAY(mpWorkingBuffer);
SAFE_DELETEARRAY(mpDecryptBuffer);
mIYDecrypt.ResetEncryptType();
LOGMSG(DBG_LEVEL_D, "%s ---\n", __PRETTY_FUNCTION__);
}
UINT32 IYDataOperator::GetBlockSize()
{
return mBlockSize;
}
UINT32 IYDataOperator::GetCacheBlockCount()
{
return mCacheBlockCount;
}
UINT32 IYDataOperator::GetRetainBlockCount()
{
return mRetainBlockCount;
}
UINT64 IYDataOperator::GetFileSize()
{
return mFileSize;
}
size_t IYDataOperator::ReadBuffer(
UINT64 uFromPos,
BYTE *pBuffer,
size_t nBufLen,
UINT64 uTimeout,
BOOL bUseContinueRead)
{
LOGMSG(DBG_LEVEL_I, "before ReadBufferNoDecrypt, uFromPos=%d\n", uFromPos);
UINT32 uReadSize = ReadBufferNoDecrypt(
uFromPos,
pBuffer,
nBufLen,
uTimeout,
bUseContinueRead);
//LOGMSG(DBG_LEVEL_I, "before mIYDecrypt.DecryptBuffer, uFromPos=%d\n", uFromPos);
if (uReadSize > 0)
{
uReadSize = mIYDecrypt.DecryptBuffer(pBuffer, uReadSize, uFromPos);
LOGMSG(DBG_LEVEL_I, "after mIYDecrypt.DecryptBuffer, uReadSize=%d\n", uReadSize);
}
return uReadSize;
}
UINT32 IYDataOperator::ReadOneBlock(
BYTE **ppWorkingBuffer,
UINT32 uBlockIndex,
UINT32 uBlockSize,
BOOL bLastBlock,
UINT64 uTimeout,
BOOL bUseContinueRead)
{
UINT32 uReadSize = 0;
UINT64 uFromPos = (UINT64)uBlockIndex * mBlockSize;
// 读取数据
if (mOSKDecryptType != 0)
{
uReadSize = ReadBuffer(
uFromPos,
mpDecryptBuffer,
uBlockSize,
uTimeout,
bUseContinueRead);
uReadSize = mOSKVideoDecrypt.DecryptBlock(
mpDecryptBuffer,
uBlockIndex,
uReadSize,
bLastBlock ? true : false,
mpWorkingBuffer);
}
else
{
uReadSize = ReadBuffer(
uFromPos,
mpWorkingBuffer,
uBlockSize,
uTimeout,
bUseContinueRead);
}
*ppWorkingBuffer = mpWorkingBuffer;
return uReadSize;
}
BOOL IYDataOperator::SupportReadRandom()
{
if (mOSKDecryptType != 0)
{
return FALSE;
}
else
{
return TRUE;
}
}
void IYDataOperator::CancelRead()
{
LOGMSG(DBG_LEVEL_I, "%s\n", __PRETTY_FUNCTION__);
mCancelRead = TRUE;
mHttpFile.CancelRead();
}
void IYDataOperator::EnableSlowRead(
BOOL bEnableSlowRead)
{
LOGMSG(DBG_LEVEL_I, "%s=%d\n", __PRETTY_FUNCTION__, bEnableSlowRead);
mEnableSlowRead = bEnableSlowRead;
}
float IYDataOperator::GetReadSpeedKBPS()
{
return mRealTimeReadSpeedKBPS;
}
size_t IYDataOperator::ReadBufferNoDecrypt(
UINT64 uFromPos,
BYTE *pBuffer,
size_t nBufLen,
UINT64 uTimeout,
BOOL bUseContinueRead)
{
LOGMSG(DBG_LEVEL_D, "%s +++\n", __PRETTY_FUNCTION__);
size_t nTotalRead = 0;
mCancelRead = FALSE;
// 读取数据
if (mBufferFileType == BufferFileType_Http)
{
mHttpFile.SeekFile(uFromPos, SEEK_SET);
}
else
{
fseeko64(mpLocalFile, uFromPos, SEEK_SET);
}
UINT64 uTime1 = GetTickCount();
while ((!mCancelRead) && (nTotalRead < nBufLen))
{
if (mEnableSlowRead)
{
// 限制 5M/s = 5K/ms 的速度读取, 减少磁盘/网络IO所造成的CPU性能下降
UINT64 uReadInterval = nTotalRead / (5*SIZE_1K);
UINT64 uReadUsedTime = GetTickCount()-uTime1;
if (uReadUsedTime < uReadInterval)
{
Sleep(uReadInterval-uReadUsedTime);
}
}
size_t nNeedRead = nBufLen-nTotalRead;
UINT32 uReadSize = 0;
nNeedRead = Get2Min(nNeedRead, STBSTREAM_NORMAL_READ_BLOCKSIZE);
uReadSize = FileRead(mpLocalFile, pBuffer+nTotalRead, nNeedRead);
mRealTimeReadSpeedKBPS = 0.0;
if (uReadSize < nNeedRead)
{
LOGMSG(DBG_LEVEL_D, "%s read NOT expect, expect=%d, actual=%d\n",
__PRETTY_FUNCTION__,
uReadSize,
nNeedRead);
break;
}
nTotalRead += uReadSize;
}
LOGMSG(DBG_LEVEL_D, "%s ---\n", __PRETTY_FUNCTION__);
return nTotalRead;
}
void* IY_DataOperator_Handle_Create()
{
IYDataOperator *pDataOperator = new IYDataOperator();
return pDataOperator;
}
void IY_DataOperator_Handle_Destroy(
void *pHandle)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return;
}
delete pDataOperator;
}
void* IY_DataOperator_Access_Open(
const char* cServerName,
const char* cFileName,
BOOL bIsPreview,
int nOSKDecryptType,
const char* cSTBDecryptOEMID)
{
IYDataOperator *pDataOperator = new IYDataOperator();
if (!pDataOperator)
{
return NULL;
}
if (pDataOperator->Open(
cServerName,
cFileName,
bIsPreview,
nOSKDecryptType,
cSTBDecryptOEMID))
{
return pDataOperator;
}
else
{
delete pDataOperator;
return NULL;
}
}
void IY_DataOperator_Access_Close(
void* pHandle)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return;
}
pDataOperator->Close();
delete pDataOperator;
}
UINT32 IY_DataOperator_Access_GetBlockSize(
void* pHandle)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return 0;
}
return pDataOperator->GetBlockSize();
}
UINT32 IY_DataOperator_Access_GetCacheBlockCount(
void* pHandle)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return 0;
}
return pDataOperator->GetCacheBlockCount();
}
UINT32 IY_DataOperator_Access_GetRetainBlockCount(
void* pHandle)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return 0;
}
return pDataOperator->GetRetainBlockCount();
}
UINT64 IY_DataOperator_Access_GetFileSize(
void* pHandle)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return 0;
}
return pDataOperator->GetFileSize();
}
ssize_t IY_DataOperator_Access_ReadBuffer(
void* pHandle,
UINT64 uFromPos,
BYTE *pBuffer,
size_t nBufLen,
UINT64 uTimeout,
BOOL bUseContinueRead)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return 0;
}
return pDataOperator->ReadBuffer(
uFromPos,
pBuffer,
nBufLen,
uTimeout,
bUseContinueRead);
}
UINT32 IY_DataOperator_Access_ReadOneBlock(
void* pHandle,
BYTE **ppWorkingBuffer,
UINT32 uBlockIndex,
UINT32 uBlockSize,
BOOL bLastBlock,
UINT64 uTimeout,
BOOL bUseContinueRead)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return 0;
}
return pDataOperator->ReadOneBlock(
ppWorkingBuffer,
uBlockIndex,
uBlockSize,
bLastBlock,
uTimeout,
bUseContinueRead);
}
BOOL IY_DataOperator_Access_SupportReadRandom(
void* pHandle)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return TRUE;
}
return pDataOperator->SupportReadRandom();
}
void IY_DataOperator_Access_CancelRead(
void* pHandle)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return;
}
return pDataOperator->CancelRead();
}
void IY_DataOperator_Access_EnableSlowRead(
void* pHandle,
BOOL bEnableSlowRead)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return;
}
return pDataOperator->EnableSlowRead(bEnableSlowRead);
}
float IY_DataOperator_Access_GetReadSpeedKBPS(
void* pHandle)
{
IYDataOperator *pDataOperator = (IYDataOperator*)pHandle;
if (!pDataOperator)
{
return 0.0;
}
return pDataOperator->GetReadSpeedKBPS();
}
void* IY_DataOperator_Process_Init(
void* pHandle)
{
return NULL;
}
void IY_DataOperator_Process_Deinit(
void* pHandle,
void *pUserData)
{
return;
}
void IY_DataOperator_Process_BufferPostCallback(
void* pHandle,
void *pUserData,
UINT64 uDataPos,
BYTE *pBuffer,
UINT32 nBufLen)
{
}
const char* CheckFileProtocol(const char* cFileName)
{
if(access(cFileName,0)!=-1)
{
return cFileName;
}
else
{
return 0;
}
}
IYDecrypt
IYDecrypt.h
#pragma once
#include "types.h"
// ENCTYPE AAAA 加密类型:尾部20个字节为密码保存区域,
// 其中,0~3:AAAA,4~19:与文件尾16个字节异或结果
//
// ENCTYPE BBBB 加密类型:尾部36个字节为密码保存区域,
// 其中,0~15:OEMID, 16~19:BBBB, 20~35:与文件尾16个字节异或结果
typedef enum eIYENCRYPTTYPE
{
IYENCRYPTTYPE_NONE=0,
IYENCRYPTTYPE_mp36,
IYENCRYPTTYPE_li6,
IYENCRYPTTYPE_ld6,
IYENCRYPTTYPE_vk6,
IYENCRYPTTYPE_mvh5
} IYENCRYPTTYPE;
class CIYDecrypt
{
public:
CIYDecrypt();
~CIYDecrypt();
public:
void ResetEncryptType();
void DetectLocalFileEncryptType(
const char* cFileName,
const char* cOEMID);
void DetectHttpFileEncryptType(
const char* cHttpUrl,
const char* cOEMID);
void DetectBufferEncryptType(
const BYTE pFileEndData[4096],
const char* cOEMID);
IYENCRYPTTYPE GetEncryptType();
size_t DecryptBuffer(
BYTE* pInOutBuf,
size_t nBufSize,
UINT64 uBufStartPos);
private:
size_t DecryptVideoBuffer(
BYTE* pInOutBuf,
size_t nBufSize,
UINT64 uBufStartPos);
private:
IYENCRYPTTYPE mEncryptType;
BYTE mEncTypePassword[16];
enum eCRYPT_TYPE
{
CRYPT_TYPE_ALL=1,
CRYPT_TYPE_2=2,
CRYPT_TYPE_64=64
} mcrypt_type;
};
IYDecrypt.cpp
#include <string.h>
#include <stdio.h>
#include "DecryptKey.h"
#include "IYDecrypt.h"
#include "DbgOutput.h"
#include "commfunc.h"
#include "FileOperator.h"
#include "HttpFileClient.h"
#include <string>
#include "aes.h"
#define CRYPT_BLOCK_LEN (1024)
/**#define CRYPT_TYPE_ALL (1)
#define CRYPT_TYPE_2 (2)
#define CRYPT_TYPE_64 (64)*/
const char *mp36_key = "6sdfwmq1pu752dqh";
const char *li6_key = "oiw93nfFEwNqt93g";
const char *ld6_key = "dsu84jvsk2s2d2sf";
const char *vk6_key = "sdA2knD93L3dsfwj";
const char *mvh5_key = "2k6Pd9A8ak7ul4Mv";
using namespace std;
CIYDecrypt::CIYDecrypt()
{
mEncryptType = IYENCRYPTTYPE_NONE;
memset(mEncTypePassword, 0, 16);
}
CIYDecrypt::~CIYDecrypt()
{
}
void CIYDecrypt::ResetEncryptType()
{
mEncryptType = IYENCRYPTTYPE_NONE;
memset(mEncTypePassword, 0, 16);
}
void CIYDecrypt::DetectLocalFileEncryptType(
const char* cFileName,
const char* cOEMID)
{
mEncryptType = IYENCRYPTTYPE_NONE;
string suffix = cFileName;
if (suffix.find('.mp36')!=string::npos)
{
mEncryptType = IYENCRYPTTYPE_mp36;
}
else if (suffix.find('.li6')!=string::npos)
{
mEncryptType = IYENCRYPTTYPE_li6;
}
else if (suffix.find('.ld6')!=string::npos)
{
mEncryptType = IYENCRYPTTYPE_ld6;
}
else if (suffix.find('.vk6')!=string::npos)
{
mEncryptType = IYENCRYPTTYPE_vk6;
}
else if (suffix.find('.mvh5')!=string::npos)
{
mEncryptType = IYENCRYPTTYPE_mvh5;
}
}
void CIYDecrypt::DetectHttpFileEncryptType(
const char* cHttpUrl,
const char* cOEMID)
{
mEncryptType = IYENCRYPTTYPE_NONE;
CHttpFileClient mHttpFile;
if (!mHttpFile.OpenFile(cHttpUrl))
{
return;
}
mHttpFile.SeekFile(0, SEEK_END);
INT64 lFilePos = mHttpFile.GetFilePos();
if (lFilePos >= 4096)
{
BYTE cPwdTag[4096];
memset(cPwdTag, 0, 4096);
// 读取尾部4096个字节做判断
mHttpFile.SeekFile(lFilePos-4096, SEEK_SET);
mHttpFile.ReadFile_Part(cPwdTag, 4096, 10000);
mHttpFile.SeekFile(0, SEEK_SET);
DetectBufferEncryptType(cPwdTag, cOEMID);
}
mHttpFile.CloseFile();
}
void CIYDecrypt::DetectBufferEncryptType(
const BYTE pFileEndData[4096],
const char* cOEMID)
{
//Not implement
}
IYENCRYPTTYPE CIYDecrypt::GetEncryptType()
{
return mEncryptType;
}
size_t CIYDecrypt::DecryptBuffer(
BYTE* pInOutBuf,
size_t nBufSize,
UINT64 uBufStartPos)
{
size_t nDecryptSize = nBufSize;
UINT64 uTime1 = GetTickCount();
//LOGMSG(DBG_LEVEL_I, "before DecryptVideoBuffer, uBufStartPos=%d\n", uBufStartPos);
if (mEncryptType != IYENCRYPTTYPE_NONE)
{
nDecryptSize = DecryptVideoBuffer(
pInOutBuf,
nBufSize,
uBufStartPos);
LOGMSG(DBG_LEVEL_I, "after DecryptVideoBuffer, uBufStartPos=%d\n", uBufStartPos);
}
LOGMSG(DBG_LEVEL_D, "decrypt buffer(%d bytes) use time(ms):%llu\n",
nBufSize, GetTickCount()-uTime1);
return nDecryptSize;
}
size_t CIYDecrypt::DecryptVideoBuffer(
BYTE* pInOutBuf,
size_t nBufSize,
UINT64 uBufStartPos)
{
size_t i;
int lyAesContentLen = 16;
int counter = 0;
AES_KEY key;
//LOGMSG(DBG_LEVEL_I, "uBufStartPos=%d\n", uBufStartPos);
if (mEncryptType == IYENCRYPTTYPE_mp36)
{
AES_set_decrypt_key((const unsigned char*)mp36_key,strlen(mp36_key) * 8, &key);
mcrypt_type = CRYPT_TYPE_2;
}
else if (mEncryptType == IYENCRYPTTYPE_li6)
{
AES_set_decrypt_key((const unsigned char*)li6_key,strlen(li6_key) * 8, &key);
mcrypt_type = CRYPT_TYPE_2;
}
else if (mEncryptType == IYENCRYPTTYPE_ld6)
{
AES_set_decrypt_key((const unsigned char*)ld6_key,strlen(ld6_key) * 8, &key);
mcrypt_type = CRYPT_TYPE_2;
}
else if (mEncryptType == IYENCRYPTTYPE_vk6)
{
AES_set_decrypt_key((const unsigned char*)vk6_key,strlen(vk6_key) * 8, &key);
mcrypt_type = CRYPT_TYPE_2;
}
else if (mEncryptType == IYENCRYPTTYPE_mvh5)
{
AES_set_decrypt_key((const unsigned char*)mvh5_key,strlen(mvh5_key) * 8, &key);
mcrypt_type = CRYPT_TYPE_64;
}
for(i=0; i<nBufSize-(nBufSize%lyAesContentLen);i+=lyAesContentLen )
{
if(counter% mcrypt_type == 0)
{
AES_decrypt(&pInOutBuf[i],&pInOutBuf[i], &key);
//LOGMSG(DBG_LEVEL_I, "AES_decrypt i=%d, count=%d\n", i, counter);
}
counter++;
}
return nBufSize;
}
aes
aes.h
#ifndef HEADER_AES_H
#define HEADER_AES_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef OPENSSL_NO_AES
#error AES is disabled.
#endif
#include <stddef.h>
#define AES_ENCRYPT 1
#define AES_DECRYPT 0
#define FULL_UNROLL 1
/* Because array size can't be a const in C, the following two are macros.
Both sizes are in bytes. */
#define AES_MAXNR 14
#define AES_BLOCK_SIZE 16
/* This should be a hidden type, but EVP requires that the size be known */
struct aes_key_st {
#ifdef AES_LONG
unsigned long rd_key[4 *(AES_MAXNR + 1)];
#else
unsigned int rd_key[4 *(AES_MAXNR + 1)];
#endif
int rounds;
};
typedef struct aes_key_st AES_KEY;
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
AES_KEY *key);
void AES_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
void AES_decrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key);
/* from aes_locl.h */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
# define GETU32(p) SWAP(*((u32 *)(p)))
# define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
#else
# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
#endif
#ifdef AES_LONG
typedef unsigned long u32;
#else
typedef unsigned int u32;
#endif
typedef unsigned short u16;
typedef unsigned char u8;
#define MAXKC (256/32)
#define MAXKB (256/8)
#define MAXNR 14
#ifdef __cplusplus
}
#endif
#endif /* !HEADER_AES_H */
总结
主要工作都集中在数据流的解析,只要理清楚层次脉络,就可以实现播放音视频的同时进行算法解密。