⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 core_mmsh.cpp

📁 ASFR+是在ASFRecorder的基础上的改进版本,它可以: ◇支持中文文件名. ◇多线程下载ASF文件. ◇断点续传,自动重试. ◇支持MMS(TCP)协议和HTTP协议(自动探测). ◇在下载
💻 CPP
📖 第 1 页 / 共 2 页
字号:
			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 + -