winamp/Src/Plugins/Input/in_flv/FileProcessor.cpp

201 lines
4.9 KiB
C++

#include "FileProcessor.h"
#include "FLVHeader.h"
#include "FLVVideoHeader.h"
static int64_t Seek64(HANDLE hf, int64_t distance, DWORD MoveMethod)
{
LARGE_INTEGER li;
li.QuadPart = distance;
li.LowPart = SetFilePointer(hf, li.LowPart, &li.HighPart, MoveMethod);
if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
{
li.QuadPart = -1;
}
return li.QuadPart;
}
int64_t FileSize64(HANDLE file)
{
LARGE_INTEGER position;
position.QuadPart=0;
position.LowPart = GetFileSize(file, (LPDWORD)&position.HighPart);
if (position.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
return INVALID_FILE_SIZE;
else
return position.QuadPart;
}
FileProcessor::FileProcessor()
{
Init();
}
FileProcessor::FileProcessor(const wchar_t *filename)
{
Init();
processedCursor=CreateFile(filename, GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
readCursor=CreateFile(filename, GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
writePosition=FileSize64(readCursor);
}
FileProcessor::~FileProcessor()
{
if (processedCursor != INVALID_HANDLE_VALUE)
CloseHandle(processedCursor);
if (readCursor != INVALID_HANDLE_VALUE)
CloseHandle(readCursor);
}
void FileProcessor::Init()
{
processedPosition=0;
processedCursor=INVALID_HANDLE_VALUE;
writePosition=0;
readCursor=INVALID_HANDLE_VALUE;
flen=0;
maxTimeStamp=0;
headerOK=false;
}
int FileProcessor::Process()
{
int64_t oldPosition = Seek64(processedCursor, 0, FILE_CURRENT);
// read file header if we're at the beginning
if (processedPosition == 0)
{
if (writePosition-processedPosition >= 9) // need at least nine bytes for the FLV file header
{
uint8_t data[9] = {0};
DWORD bytesRead=0;
ReadFile(processedCursor, data, 9, &bytesRead, NULL);
if (header.Read(data, bytesRead))
{
headerOK=true;
Nullsoft::Utility::AutoLock lock(frameGuard);
processedPosition += bytesRead;
return FLV_OK; // we'll make our logic just a little bit more sane by only processing one frame per pass.
}
else
return FLV_ERROR;
}
Seek64(processedCursor, oldPosition, FILE_BEGIN); // rollback
return FLV_NEED_MORE_DATA;
}
if (writePosition-processedPosition >= 15) // need at least fifteen bytes for the FLV frame header
{
uint8_t data[15] = {0};
DWORD bytesRead=0;
ReadFile(processedCursor, data, 15, &bytesRead, NULL);
FrameData frameData;
if (frameData.header.Read(data, bytesRead))
{
if (frameData.header.dataSize + processedPosition + 15 <= writePosition)
{
frameData.keyFrame = false;
if (frameData.header.type == FLV::FRAME_TYPE_VIDEO)
{
FLVVideoHeader videoHeader;
DWORD videoHeaderRead=0;
ReadFile(processedCursor, data, 1, &videoHeaderRead, NULL);
if (videoHeader.Read(data, bytesRead))
{
if (videoHeader.frameType == FLV::VIDEO_FRAMETYPE_KEYFRAME)
{
frameData.keyFrame = true;
}
}
Seek64(processedCursor, -(int64_t)videoHeaderRead, FILE_CURRENT);
// roll back file cursor from ReadFile
}
{ // critsec enter
Nullsoft::Utility::AutoLock lock(frameGuard);
// record the offset where we found it
frameData.location = processedPosition;
maxTimeStamp=max(maxTimeStamp, frameData.header.timestamp);
frames.push_back(frameData);
} // critsec leave
Seek64(processedCursor, frameData.header.dataSize, FILE_CURRENT);
Nullsoft::Utility::AutoLock lock(frameGuard);
processedPosition+=bytesRead+frameData.header.dataSize;
return FLV_OK;
}
Seek64(processedCursor, oldPosition, FILE_BEGIN); // rollback
return FLV_NEED_MORE_DATA;
}
else
{
return FLV_ERROR;
}
}
Seek64(processedCursor, oldPosition, FILE_BEGIN); // rollback
return FLV_NEED_MORE_DATA;
}
uint32_t FileProcessor::GetMaxTimestamp()
{
return maxTimeStamp;
}
bool FileProcessor::GetFrame(size_t frameIndex, FrameData &frameData)
{
Nullsoft::Utility::AutoLock lock(frameGuard);
if (frameIndex < frames.size())
{
frameData = frames[frameIndex];
return true;
}
return false;
}
uint64_t FileProcessor::GetProcessedPosition()
{
Nullsoft::Utility::AutoLock lock(frameGuard);
return processedPosition;
}
size_t FileProcessor::Read(void *data, size_t bytes)
{
DWORD bytesRead = 0;
ReadFile(readCursor, data, (DWORD)bytes, &bytesRead, NULL);
return bytesRead;
}
uint64_t FileProcessor::Seek(uint64_t position)
{
return Seek64(readCursor, position, FILE_BEGIN);
}
bool FileProcessor::GetPosition(int time_in_ms, size_t *frameIndex, bool needVideoKeyFrame)
{
Nullsoft::Utility::AutoLock lock(frameGuard);
// TODO: binary search
for (size_t f=0;f!=frames.size();f++)
{
if (frames[f].header.timestamp >= (uint32_t)time_in_ms)
{
if (needVideoKeyFrame)
{
while (f != 0 && !frames[f].keyFrame)
f--;
}
*frameIndex = f;
return true;
}
}
return false;
}
FLVHeader *FileProcessor::GetHeader()
{
if (headerOK)
return &header;
else
return 0;
}