📄 core_mmsh.cpp
字号:
unsigned int StartTime = 0xffffffff;
unsigned int StartSeqNO = 0xffffffff;
//unsigned int EndOfHeaderPosition = 0;
unsigned long HeaderLength = 0;
unsigned int HeaderOffset = 0;
/* The main loop for chunk extraction/ASF generation */
for (;;)
{
unsigned short Type;
unsigned int Length, Length2;
unsigned int BodyLength;
unsigned int SeqNO;
unsigned short PartFlag;
unsigned long TimeCode=0;
unsigned int Progress; /* scaled from 0 to 10000 */
unsigned int Got;
/* Check for EOF and extract chunk header bytes are read one by one so this code remains portable to non-INTEL platforms */
if (eos(&Stream_Parm))
{
gui_showstatus(STATUS_CRITICALERROR, "Connection reset\n");
break;
}
{ /* read basic chunk type */
unsigned char c1, c2;
readfromstream(&Stream_Parm, &c1, 1);
readfromstream(&Stream_Parm, &c2, 1);
Type = (c2<<8) + c1;
/* These header types correspond to "H$", "D$" and "E$" (Header, Data and End) */
if ((Type != MMSH_HEADER_CHUNK) && (Type != MMSH_DATA_CHUNK) && (Type != MMSH_END_CHUNK))
gui_showstatus(STATUS_ERROR, "Unknown header type: %02X:%02X\n", c2, c1);
}
if (Type == MMSH_END_CHUNK)
{
gui_showstatus(STATUS_FINISH, "Transfer complete.\n");
My_ti->Reply = REPLY_FINISH;
break;
}
if (eos(&Stream_Parm))
{
gui_showstatus(STATUS_CRITICALERROR, "Connection reset\n");
break;
}
{ /* read chunk length (max 64k) */
unsigned char l1, l2;
readfromstream(&Stream_Parm, &l1, 1);
readfromstream(&Stream_Parm, &l2, 1);
Length = (l2<<8) + l1;
}
if (eos(&Stream_Parm))
{
gui_showstatus(STATUS_CRITICALERROR, "Connection reset\n");
break;
}
{ /* read chunk sequence number */
unsigned char s1, s2, s3, s4;
readfromstream(&Stream_Parm, &s1, 1);
readfromstream(&Stream_Parm, &s2, 1);
readfromstream(&Stream_Parm, &s3, 1);
readfromstream(&Stream_Parm, &s4, 1);
SeqNO = (s4<<24) + (s3<<16) + (s2<<8) + s1;
}
if (eos(&Stream_Parm))
{
gui_showstatus(STATUS_CRITICALERROR, "Connection reset\n");
break;
}
{ /* read two unknown bytes */
unsigned char u1, u2;
readfromstream(&Stream_Parm, &u1, 1);
readfromstream(&Stream_Parm, &u2, 1);
PartFlag = (u2<<8) + u1;
}
if (eos(&Stream_Parm))
{
gui_showstatus(STATUS_CRITICALERROR, "Connection reset\n");
break;
}
{ /* read second length entry (length confirmation) */
unsigned char l1, l2;
readfromstream(&Stream_Parm, &l1, 1);
readfromstream(&Stream_Parm, &l2, 1);
Length2 = (l2<<8) + l1;
}
if (eos(&Stream_Parm))
{
gui_showstatus(STATUS_CRITICALERROR, "Connection reset\n");
break;
}
/* Sanity check on chunk header. Second length entry must match the first. */
if (Length2 != Length)
{
gui_showstatus(STATUS_CRITICALERROR, "Length confirmation doesn't match!\n");
break;
}
/* calculate length of chunk body. */
BodyLength = Length-8;
/* check if the body length exceeds our buffer size */
if ((BodyLength > MAX_CHUNK_SIZE) || (BodyLength <= 0))
{
gui_showstatus(STATUS_CRITICALERROR, "Illegal ChunkLength. Chunk is %d bytes!\n", Length);
break;
}
/* Read chunk's body data */
if (Type != MMSH_HEADER_CHUNK) HeaderOffset = 0;
Got = readfromstream(&Stream_Parm, Buffer + HeaderOffset, BodyLength);
BodyLength += HeaderOffset;
Got += HeaderOffset;
if (Type == MMSH_HEADER_CHUNK && My_ti->RequestType == REQUEST_INFORMATION)
{
/* Headers may be split into several parts with a rising sequence number. */
if (PartFlag & 0x0400) /* This indicates the first header part */
{
HeaderOffset = 0;
get_long(&Buffer[0x10], &HeaderLength);
HeaderLength += DATSEG_HDR_SIZE;
}
if (BodyLength < HeaderLength) /* header progress indicator */
gui_showstatus(STATUS_INFORMATION, "receiving ASF header (%d/%d)!\n", BodyLength, HeaderLength);
if (!(PartFlag & 0x0800)) /* Skip parsing the header if it hasn't been received completely */
{
HeaderOffset = BodyLength; /* next header partition will be appended */
BodyLength = HeaderLength; /* this prevents saving a partial header to the output file */
}
else
{
int Offs;
/* finally got the header */
gui_showstatus(STATUS_INFORMATION, "received ASF header!\n");
/* find a specific object in this header */
Offs = find_id(ASF_HDR_ID,Buffer, Got);
if (Offs == -1)
{
gui_showstatus(STATUS_CRITICALERROR, "Unable to parse this ASF header!\n");
break;
}
/* extract required information */
My_ci->HeaderOffs = Offs;
//get_quad(&Buffer[Offs+HDR_TOTAL_SIZE_8], &My_ci->TotalSizeHi, &My_ci->TotalSizeLo);
get_quad(&Buffer[Offs+HDR_FINE_TOTALTIME_8], &My_ci->TotalTimeHi, &My_ci->TotalTimeLo);
get_long(&Buffer[Offs+HDR_PLAYTIME_OFFSET_4], &My_ci->Offset);
get_long(&Buffer[Offs+HDR_FLAGS_4], &My_ci->Flags);
get_long(&Buffer[Offs+HDR_ASF_CHUNKLENGTH_4], &My_ci->ChunkLength);
get_long(&Buffer[Offs+HDR_ASF_CHUNKLENGTH_CONFIRM_4], &My_ci->ChunkLength2);
unsigned long NumOfPacket;
get_long(&Buffer[Offs+HDR_NUM_PACKETS_8], &NumOfPacket);
My_ci->TotalSizeLo = BodyLength + NumOfPacket*My_ci->ChunkLength;
My_ci->TotalSizeHi = 0;
My_hi->FileSize = My_ci->TotalSizeLo;
/* check if the extracted chunk length looks good */
if ((My_ci->ChunkLength > MAX_CHUNK_SIZE) && (My_ci->ChunkLength != My_ci->ChunkLength2))
{
gui_showstatus(STATUS_CRITICALERROR, "Illegal chunk sizes, %d, %d\n", My_ci->ChunkLength, My_ci->ChunkLength2);
break;
}
/* calculate playtime in milliseconds (0 for live streams) */
if (My_ci->TotalTimeHi == 0 && My_ci->TotalTimeLo == 0)
My_ci->Time = 0; /* live streams */
else
My_ci->Time = (int)((double)429496.7296 * My_ci->TotalTimeHi) + (My_ci->TotalTimeLo / 10000) - My_ci->Offset;
/* store position where the ASF header segment ends and the chunk data segment starts */
My_ci->EndOfHeaderOffs = BodyLength - DATSEG_HDR_SIZE;
My_ti->Reply = REPLY_OK;
break;
}
}
/* Try to extract a timecode from all known chunk/content types(only applies to data chunks) */
if (Type == MMSH_DATA_CHUNK)
{
ustrcpy(TimeCodeString, "?????");
TimeCode = 0;
int TCStart;
if (My_ti->RequestType == REQUEST_INFORMATION) continue;
/* save the first seqno available as a reference */
if (StartSeqNO == 0xffffffff) StartSeqNO = SeqNO;
/* fix the seqno for live recordings only */
if (My_ci->Time == 0) SeqNO -= StartSeqNO; /* refer seqno to the point we "zapped in" (for live streams) */
/* find the location of the time code */
if ((TCStart = whereis_timecode(Buffer)) > 0)
{
/* The timecode is an integer value defining milliseconds enough range for about 50 days! */
get_long(&Buffer[TCStart], &TimeCode);
/* save the first timecode available as a reference */
if (StartTime == 0xffffffff) StartTime = TimeCode;
/* fix timecode for live recordings only */
if (My_ci->Time == 0)
{
TimeCode -= StartTime; /* refer timecode to the point we "zapped in" (live streams) */
fix_timecodes(Buffer, BodyLength, StartTime, SeqNO, My_ci); /* fixes the timecodes in the memory buffer */
}
/* save max. timecode value */
if (TimeCode > My_ci->MaxTimeCode)
My_ci->MaxTimeCode = TimeCode;
/* create a string with a human-readable form of the timecode */
ustrcpy(TimeCodeString, createtimestring(TimeCode));
}
}
/* calculate progress indicator (scale: 0....10000) */
if (My_ci->Time == 0) /* this mean a live record */
{
if (My_Job->MaxTime == 0) /* unlimited recording */
Progress = 0;
else /* limited time recording */
Progress = (int)((double)TimeCode*10000/(My_Job->MaxTime*60*1000));
}
else
Progress = (int)(((double)(SeqNO+1)*My_ci->ChunkLength+My_ci->EndOfHeaderOffs+DATSEG_HDR_SIZE) / My_hi->FileSize * 10000);
/* Print current position in stream download */
gui_showstatus(STATUS_INFORMATION, "%d | %7ldKB | %2d.%02d%% | HDR:%c:%c | %5dBYTES | SEQ:%06X | TC:%s\n",
MyID,
max( (signed long)(SeqNO+1)*My_ci->ChunkLength - My_ti->DestOffset, 0 )/1024 + 1,
Progress / 100,
Progress % 100,
Type >> 8, Type,
BodyLength,
SeqNO,
TimeCodeString );
/* some statistics for data chunks only */
if (Type == MMSH_DATA_CHUNK)
{
/* check chunk body for completeness */
if (Got < BodyLength && My_Job->OutFile != NULL)
{
gui_showstatus(STATUS_ERROR, "Received incomplete chunk... (Chunk is NOT saved)\n");
continue;
}
My_ci->NumDataChunks++; /* count number of chunks */
My_ci->SizeOfDataChunks += My_ci->ChunkLength; /* count total size of chunks */
}
if (My_Job->OutFile != NULL)
{
/* lock other threads from writing */
MUTEX
char ThisChunkFlag;
unsigned char *ThisChunkPtr;
unsigned long ThisChunkPos;
unsigned long ThisChunkSize;
switch (Type)
{
case MMSH_HEADER_CHUNK:
ThisChunkPos = 0;
ThisChunkPtr = Buffer;
if(My_ti->SourOffset == 0) /* Is this the request for first segment? */
{
unsigned char c1=0, c2=0, c3=0, c4=0;
/* a dirty hack to find all "MP43" and change to "DIV3" in header */
for ( i=0 ; i<=Got ; ++i ) {
c4=c3 ; c3=c2 ; c2=c1;
c1=Buffer[i];
if( 'M'==c4 && 'P'==c3 && '4'==c2 && '3'==c1 ) {
Buffer[i-3]='D';
Buffer[i-2]='I';
Buffer[i-1]='V';
Buffer[i]='3';
}
}
ThisChunkSize = Got;
}
else
ThisChunkSize = 0; /* Just ignore it */
break;
case MMSH_DATA_CHUNK:
/* calculate appropriate position in file */
ThisChunkPos = My_ci->EndOfHeaderOffs + DATSEG_HDR_SIZE + SeqNO * My_ci->ChunkLength;
ThisChunkSize = My_ci->ChunkLength;
ThisChunkPtr = Buffer;
/* Get Data chunk's Padding Flags. */
ThisChunkFlag = Buffer[3];
/* Convert 0x40 chunk to Non-0x40 form, VirtualDub dont recognize this type */
if (ThisChunkFlag & 0x40)
{
for (i=5 ; i<Got ; i++) Buffer[i]=Buffer[i+2];
Buffer[3] = ThisChunkFlag - 0x40;
Got -= 2;
BodyLength -= 2;
}
/* Fix the padding size. */
if (ThisChunkFlag & 0x18)
{
short int PaddingSize = ThisChunkSize-BodyLength;
Buffer[5] = (char)(PaddingSize & 0xff);
if (ThisChunkFlag & 0x10) Buffer[6]=(char)(PaddingSize >> 8);
}
/* Fill up unused bytes in this chunk. ASF requires equally sized DATA chunks */
memset((char *)(ThisChunkPtr + Got), 0, (ThisChunkSize - Got));
break;
default:
ThisChunkPos = MyFilePointer;
ThisChunkSize = Got;
ThisChunkPtr = Buffer;
}
/* Since the server always send a full chunk, We sometimes just need latter part of this chunk */
if (ThisChunkPos < My_ti->SourOffset)
{
if ((ThisChunkPos + ThisChunkSize) < My_ti->SourOffset)
{
if(Type != MMSH_HEADER_CHUNK) gui_showstatus(STATUS_INFORMATION, "(%d) Chunk position below range, ignored.\n", MyID);
ThisChunkPos = 0;
ThisChunkSize = 0;
}
else
{
ThisChunkPtr += (My_ti->SourOffset - ThisChunkPos);
ThisChunkSize -= (My_ti->SourOffset - ThisChunkPos);
ThisChunkPos = My_ti->SourOffset;
}
}
/* We sometimes just need header part of this chunk */
if ((ThisChunkPos + ThisChunkSize) > (My_ti->SourOffset + My_ti->DestLength))
{
if (ThisChunkPos > (My_ti->SourOffset + My_ti->DestLength))
{
gui_showstatus(STATUS_INFORMATION, "(%d) Chunk position over range, ignored.\n", MyID);
ThisChunkPos = 0;
ThisChunkSize = 0;
}
else
{
ThisChunkSize -= ((ThisChunkPos + ThisChunkSize) - (My_ti->SourOffset + My_ti->DestLength));
}
}
/* perform write action */
fseek(My_Job->OutFile, ThisChunkPos-My_ti->DestOffset, SEEK_SET);
fwrite(ThisChunkPtr, ThisChunkSize, 1, My_Job->OutFile);
MyFilePointer = ThisChunkPos + ThisChunkSize;
My_ti->SourOffset += ThisChunkSize;
My_ti->DestLength -= ThisChunkSize;
/* unlock other threads */
DEMUTEX
}
/* set a new total time for the stream (important for preview and slider functionality)
if (My_ci->Time == 0)
{
if (My_Job->MaxTime == 0)
gui_modify_duration(TimeCode);
else
gui_modify_duration(My_Job->MaxTime*60*1000);
} */
/* Check whether dest_length reached */
if( !My_ti->DestLength )
{
gui_showstatus(STATUS_INFORMATION, "Segment finished.\n");
My_ti->Reply = REPLY_SEGMENTFINISH;
break;
}
/* use recording time limit, if specified */
if ( (My_Job->MaxTime != 0) && ((int)TimeCode >= (My_Job->MaxTime*60*1000)) )
{
My_ti->DestLength = 0;
gui_showstatus(STATUS_INFORMATION, "maxtime reached.\n");
My_ti->Reply = REPLY_EXIT;
break;
}
/* Receive Message from Job */
if(My_ti->Message == MESSAGE_PAUSE)
while(My_ti->Message != MESSAGE_CONTINUE) usleep(50);
if(My_ti->Message == MESSAGE_EXIT || My_ti->Message == MESSAGE_CANCEL)
{
//printf("I'm die! ID:%d\n", MyID);
My_ti->Reply = REPLY_EXIT;
break;
}
} /* for (;;) */
/* Cleanup */
my_closesocket(ConnSocket);
free(Stream_Parm.si);
break;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
case REQUEST_FINISH:
{
/* fix total file size and for live streams the header information as well */
if ( My_Job->OutFile != NULL )
{
unsigned long FileSizeHi = 0;
unsigned long FileSizeLo;
/* Determine file size of .ASF file */
fseek(My_Job->OutFile, 0, SEEK_END);
FileSizeLo = ftell(My_Job->OutFile);
/* write correct file size in ASF header */
fseek(My_Job->OutFile, My_ci->HeaderOffs + HDR_TOTAL_SIZE_8, SEEK_SET);
write_quad(My_Job->OutFile, FileSizeHi, FileSizeLo);
/* enable seeking in file */
fseek(My_Job->OutFile, My_ci->HeaderOffs + HDR_FLAGS_4, SEEK_SET);
write_long(My_Job->OutFile, 0x00000002);
}
break;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} /* switch(RequestType)*/
/* Cleanup & exit */
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -