HTTP Streaming例子: AsfRecorder.c代码

    技术2022-05-11  62

      AsfRecorder.c 研究  v1.1 开源项目, 代码来自: http://sourceforge.net/projects/asfrecorder/ 主要实现下载 http stream file   /* The core routine for ASF download/extraction. */   int collectdata(int headeronly,                 int dumpheaders,                 FILE *rawfile,                 FILE *outfile,                 int bytesread,                unsigned char *Buffer,                 int bufsize,                 int sendlen,                 struct hostent *hp,                 char *server_name,                 unsigned int addr,                 unsigned short port,                 int socket_type,                 char *file,                 struct HeaderInfo *hi,                 int maxtime) {     SOCKET conn_socket;     int retval;       SOCKADDR_IN server;       int eol;     int hdrpos;     int linepos;     int linenum;     char HTTPHeader[1024];     int resume = 0;       char HTTPLine[512];     char HTTPMessage[128];     char *hdrptr;     int errorcode;      ...   conn_socket = my_socket(AF_INET,socket_type,0); /* Open a socket */ ...    retval = my_send(conn_socket,Buffer,sendlen,0);                        for (;;)                 {                     char c;                       if (readfromstream(conn_socket, &c, 1, rawfile) == 1)                     {                         if ((c != '/r') && (c != '/n'))                         {                             eol = 0;                             HTTPLine[linepos++] = c;                         }                         else                             HTTPLine[linepos++] = 0;                           if (c == '/n')                         {                             if (eol == 0)                             {                                 linepos = 0;                                 eol = 1;                                 linenum++;                                   hdrptr = HTTPLine;                                   /* Parse first line of HTTP reply */                                 if (linenum == 1)                                 {                                     if ((!strnicmp(hdrptr, "HTTP/1.0 ", 9)) ||                                         (!strnicmp(hdrptr, "HTTP/1.1 ", 9))   )                                     {                                         hdrptr+=9;                                         sscanf(hdrptr, "%d", &errorcode);                                         hdrptr+=4;                                         strcpy(HTTPMessage, hdrptr);                                     }                                     else                                     {                                         gui_seterror("Illegal server reply! Expected HTTP/1.0 or HTTP/1.1/n");                                         hi->contenttype = unknown_content;                                     }                                 }                                 else                                 {                                     /* Parse all other lines of HTTP reply */                                     if (!strnicmp(hdrptr, "Content-Type: ", 14))                                     {                                         hdrptr+=14;                                         strncpy(ContentType, hdrptr, sizeof(ContentType));                                     }                                       /* Parse all other lines of HTTP reply */                                     if (!strnicmp(hdrptr, "Pragma: ", 8))                                     {                                         hdrptr+=8;                                         if (!strnicmp(hdrptr, "features=", 9))                                         {                                             hdrptr+=9;                                             strncpy(Features, hdrptr, sizeof(Features));                                         }                                     }                                 }                             }                             else                             {                                 HTTPHeader[hdrpos++] = 0;                                 break;                             }                         }                           HTTPHeader[hdrpos++] = c;                     }                     else                     {                         gui_seterror("readfromstream() returned other than 1!/n");                         if (eos()) break;                     }                 }                   hi->contenttype = unknown_content;                   /* Determine whether this is live content or not */                 if (!stricmp(ContentType, "application/octet-stream"))                 {                     if (strstr(Features, "broadcast"))                     {                         hi->contenttype = live_content;                     }                     else                     {                         hi->contenttype = prerecorded_content;                     }                 }                 else                 {                                        ...                 }                   ...                   /* handle live or prerecorded content */                 if ((!eos()) && ((hi->contenttype == live_content) || (hi->contenttype == prerecorded_content)) )                 {                     unsigned int starttime_hi = 0xffffffff;                     unsigned int starttime    = 0xffffffff;                     unsigned int startseqno   = 0xffffffff;                     unsigned int maxtimecode = 0;                     int          endofheaderposition = 0;                     int          numdatachunks       = 0;                     int          sizeofdatachunks    = 0;                       int          header_length = 0;                     int          header_offset = 0;                       /* The main loop for chunk extraction/ASF generation */                     for (;;)                     {                        ...                           /* Check for EOF and extract chunk header */                         /* bytes are read one by one so this code */                         /* remains portable to non-INTEL platforms */                           if (eos()) { gui_setstatus("Connection reset/n"); break; }                           /* read basic chunk type */                         readfromstream(conn_socket, &c1, 1, rawfile);                         readfromstream(conn_socket, &c2, 1, rawfile);                         type = (c2<<8) + c1;                           /* These header types correspond to "H$", "D$" and "E$" */                         /* (Header, Data and End) */                         if ((type != HEADER_CHUNK) && (type != DATA_CHUNK) && (type != END_CHUNK))                         {                             gui_logtext("Unknown header type: $x/n", type);                         }                           if (type == END_CHUNK)                         {                             gui_setstatus("Transfer complete./n");                             break;                         }                           if (eos()) { gui_setstatus("Connection reset/n"); break; }                           /* read chunk length (max 64k) */                         readfromstream(conn_socket, &l1, 1, rawfile);                         readfromstream(conn_socket, &l2, 1, rawfile);                         length = (l2<<8) + l1;                           if (eos()) { gui_setstatus("Connection reset/n"); break; }                           /* read chunk sequence number */                         readfromstream(conn_socket, &s1, 1, rawfile);                         readfromstream(conn_socket, &s2, 1, rawfile);                         readfromstream(conn_socket, &s3, 1, rawfile);                         readfromstream(conn_socket, &s4, 1, rawfile);                         seqno   = (s4<<24) + (s3<<16) + (s2<<8) + s1;                           if (eos()) { gui_setstatus("Connection reset/n"); break; }                           /* read two unknown bytes */                         readfromstream(conn_socket, &u1, 1, rawfile);                         readfromstream(conn_socket, &u2, 1, rawfile);                         partflag = (u2<<8) + u1;                           if (eos()) { gui_setstatus("Connection reset/n"); break; }                           /* read second length entry (length confirmation) */                         readfromstream(conn_socket, &l1, 1, rawfile);                         readfromstream(conn_socket, &l2, 1, rawfile);                         length2 = (l2<<8) + l1;                           if (eos()) { gui_setstatus("Connection reset/n"); break; }                           /* Sanity check on chunk header. Second length entry must match the first. */                         if (length2 != length)                         {                             gui_logtext("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 > bufsize)                         {                             gui_logtext("Buffer too small. Chunk is %d bytes!/n", length);                             break;                         }                           /* check length of chunk body */                         if (bodylength <= 0)                         {                             gui_logtext("Chunk has no body!/n");                             break;                         }                           /* Read chunk's body data */                         if (type != HEADER_CHUNK) header_offset = 0;                         got = readfromstream(conn_socket, Buffer + header_offset, bodylength, rawfile);                         bodylength = header_offset + bodylength;                         got        = header_offset + got;                           /* Try to extract a timecode from all known chunk/content types */                         strcpy(timecodestring, "???");                         timecode = 0;                           /* this only applies to data chunks */                         if (type == DATA_CHUNK)                         {                             int tc_start;                               if (headeronly) break;                               /* save the first seqno available as a reference */                             if (startseqno == 0xffffffff)                             {                                 startseqno = seqno;                             }                               /* fix the seqno for live recordings only */                             if (hi->time == 0)                             {                                 /* refer seqno to the point we "zapped in" (for live streams) */                                 if (startseqno != 0xffffffff)                                     seqno -= startseqno;                             }                               /* find the location of the time code */                             if ((tc_start = whereis_timecode(Buffer)) > 0)                             {                                 /* The timecode is an integer value defining milliseconds */                                 /* enough range for about 50 days! */                                 get_long(&Buffer[tc_start], &timecode);                                   /* save the first timecode available as a reference */                                 if (starttime == 0xffffffff)                                     starttime = timecode;                                   /* fix timecode for live recordings only */                                 if (hi->time == 0)                                 {                                     /* refer timecode to the point we "zapped in" (live streams) */                                     timecode -= starttime;                                       /* this fixes the timecodes in the memory buffer */                                     fix_timecodes(Buffer, bodylength, starttime, seqno, hi);                                 }                                   /* save max. timecode value */                                 if (timecode > maxtimecode)                                     maxtimecode = timecode;                                   /* create a string with a human-readable form of the timecode */                                 strcpy(timecodestring, createtimestring(timecode));                             }                         }                           /* calculate progress indicator (scale: 0....10000) */                         if (hi->time == 0)                              /* live streams */                             if (maxtime == 0)   /* unlimited recording */                                 progress = 0;                             else                /* limited time recording */                                 progress = (int)((double)timecode*10000/(maxtime*60*1000));                         else                             /* prerecorded content */                             progress = (int)((double)timecode*10000/hi->time);                           /* Print current position in stream download */                         gui_logtext("] kB (-%%), HDR: $x, part: $x, M bytes, seq $x, tc: %s/n", bytesread/1024, progress/100, (int)type, (int)partflag, length, seqno, timecodestring);                           /* Extract the block size from the ASF header. */                         /* This block size is essential in the ASF file */                         /* format. All data chunks in the ASF file must */                         /* have this length, even if network transmission */                         /* sent us smaller chunks! */                         if (type == HEADER_CHUNK)                         {                             int offs;                                                         /* Headers may be split into several parts with */                             /* a rising sequence number. This case occurs in */                             /* audio books on broadcast.com, for example. */                               /* This indicates the first header part */                             if (partflag & 0x0400)                             {                                 header_offset = 0;                                 get_long(&Buffer[16], &header_length);                                 header_length += 50;                             }                               /* header progress indicator */                             if (bodylength < header_length)                                 gui_setstatus("receiving ASF header (%d/%d)!/n", bodylength, header_length);                               /* Skip parsing the header if it hasn't been received completely */                             if (!(partflag & 0x0800))                             {                                 /* next header partition will be appended */                                 header_offset = bodylength;                                   /* this prevents saving a partial header to the output file */                                 bodylength = header_length;                             }                             else                             {                                 /* finally got the header */                                 gui_setstatus("received ASF header!/n");                                   /* find a specific object in this header */                                 offs = find_id(HDR_ID,Buffer, got);                                 if (offs == -1)                                 {                                     gui_criticalerror("Unable to parse this ASF header!/n");                                     break;                                 }                                 else                                 {                                     /* extract required information */                                     hi->header_offs = offs;                                     get_quad(&Buffer[offs+HDR_TOTAL_SIZE_8], &hi->totalsize_hi, &hi->totalsize_lo);                                     get_quad(&Buffer[offs+HDR_FINE_TOTALTIME_8], &hi->totaltime_hi, &hi->totaltime_lo);                                     get_long(&Buffer[offs+HDR_PLAYTIME_OFFSET_4], &hi->offset);                                     get_long(&Buffer[offs+HDR_FLAGS_4], &hi->flags);                                     get_long(&Buffer[offs+HDR_ASF_CHUNKLENGTH_4], &hi->chunklength);                                     get_long(&Buffer[offs+HDR_ASF_CHUNKLENGTH_CONFIRM_4], &hi->chunklength2);                                                                         /* check if the extracted chunk length looks good */                                     if (!(hi->chunklength < MAX_CHUNK_SIZE && (hi->chunklength == hi->chunklength2)))                                     {                                         gui_criticalerror(                                             "Unable to capture this stream!/n"                                             "This one uses variable chunk sizes,/n"                                             "which is not supported. Sorry! ;-)/n");                                                                                 hi->contenttype = unknown_content;                                         break;                                     }                                                                         /* calculate playtime in milliseconds (0 for live streams) */                                     if (hi->totaltime_hi == 0 && hi->totaltime_lo == 0)                                     {                                         hi->time = 0; /* live streams */                                     }                                     else                                         hi->time = (int)((double)429496.7296 * hi->totaltime_hi) + (hi->totaltime_lo / 10000) - hi->offset;                                       /* store position where the ASF header segment ends */                                     /* and the chunk data segment starts */                                     hi->endofheader_offs = bodylength - DATSEG_HDR_SIZE;                                                                         if (!headeronly)                                         gui_setstatus("receiving stream.../n");                                     else                                         break;                                 }                             }                         }                           /* check chunk body for completeness */                         if (got < bodylength)                         {                             if (outfile != NULL && type == DATA_CHUNK)                                 gui_logtext("Received incomplete chunk... (Chunk is NOT saved)/n");                         }                         else                         {                             /* Ignore media type header if the download */                             /* resumes a previous transmission */                             if (type == HEADER_CHUNK && resume)                             {                                 gui_logtext("Not saving header since this is a RESUME./n");                             }                             else                             {                                 /* count how many bytes we accepted from server */                                 bytesread += got;                                   /* some statistics for data chunks only */                                 if (type == DATA_CHUNK)                                 {                                     /* count number of chunks */                                     numdatachunks++;                                       /* count total size of chunks */                                     sizeofdatachunks += hi->chunklength;                                 }                                   if (outfile != NULL)                                 {                                     if (type == DATA_CHUNK)                                     {                                         /* When saving data chunks, seek to appropriate position */                                         /* in file. This should prevent problems when resuming to */                                         /* download files containing a truncated last chunk */                                         fseek(outfile, hi->endofheader_offs + DATSEG_HDR_SIZE + seqno * hi->chunklength, SEEK_SET);                                     }                                       /* Save chunk body to ASF file */                                     fwrite(Buffer, 1, got, outfile);                                       /* Fill up unused bytes in this chunk. */                                     /* ASF requires equally sized chunks for */                                     /* the main stream content */                                     if (type == DATA_CHUNK && got < (int)hi->chunklength)                                     {                                         int i;                                         for (i=0; i < (int)hi->chunklength-got; i++) fputc(0, outfile);                                     }                                 }                                   /* send progress information to main GUI */                                 gui_progressinfo(bytesread, timecodestring, progress, seqno, timecode);                                   /* set a new total time for the stream */                                 /* (important for preview and slider functionality) */                                 if (hi->time == 0)                                 {                                     if (maxtime == 0)                                         gui_modify_duration(timecode);                                     else                                         gui_modify_duration(maxtime*60*1000);                                 }                             }                         }                           /* use recording time limit, if specified */                         if (maxtime != 0)                         {                             if ((int)timecode >= (maxtime*60*1000))                             {                                 gui_setstatus("maxtime reached./n");                                 break;                             }                         }                           /* check for end request */                         if (abortflag) break;                       } /* for (;;) */                       /* fix total file size and for live streams the header information as well */                     if (outfile != NULL)                     {                         unsigned int filesize_lo;                         unsigned int filesize_hi;                           /* Determine file size of .ASF file */                         fseek(outfile, 0, SEEK_END);                         filesize_hi = 0;                         filesize_lo = ftell(outfile);                           /* write this file size to the ASF header */                         fseek(outfile, hi->header_offs + HDR_TOTAL_SIZE_8, SEEK_SET);                         write_quad(outfile, filesize_hi, filesize_lo);                           /* Correct some details for live streams */                         if (hi->time == 0)                         {                             double totaltime;                             unsigned int totaltime_hi;                             unsigned int totaltime_lo;                               double playtime;                             unsigned int playtime_hi;                             unsigned int playtime_lo;                               unsigned int num_chunks_hi;                             unsigned int num_chunks_lo;                               unsigned int segmentsize_hi;                             unsigned int segmentsize_lo;                               /* bugfixed calculations, these were broken in V 1.0 */                             totaltime = (double)(maxtimecode) * 10000;                             totaltime_hi = (int)(totaltime / 4294967296.0);                             totaltime_lo = (int)(totaltime - ((double)totaltime_hi * 4294967296.0));                               playtime = (double)(maxtimecode - hi->offset) * 10000;                             playtime_hi = (int)(playtime / 4294967296.0);                             playtime_lo = (int)(playtime - ((double)playtime_hi * 4294967296.0));                               num_chunks_hi = 0;                             num_chunks_lo = numdatachunks;                               /* write correct number of packets for stream */                             fseek(outfile, hi->header_offs + HDR_NUM_PACKETS_8, SEEK_SET);                             write_quad(outfile, num_chunks_hi, num_chunks_lo);                               /* write correct totaltime for stream */                             fseek(outfile, hi->header_offs + HDR_FINE_TOTALTIME_8, SEEK_SET);                             write_quad(outfile, totaltime_hi, totaltime_lo);                               /* write correct playtime for stream */                             fseek(outfile, hi->header_offs + HDR_FINE_PLAYTIME_8, SEEK_SET);                             write_quad(outfile, playtime_hi, playtime_lo);                               /* enable seeking in file */                             fseek(outfile, hi->header_offs + HDR_FLAGS_4, SEEK_SET);                             write_long(outfile, 0x00000002);                               /* write total size of data chunk segment */                             segmentsize_hi = 0;                             segmentsize_lo = DATSEG_HDR_SIZE + sizeofdatachunks;                             fseek(outfile, hi->endofheader_offs + 0x10, SEEK_SET);                             write_quad(outfile, segmentsize_hi, segmentsize_lo);                               /* write total number of chunks */                             fseek(outfile, hi->endofheader_offs + DATSEG_NUMCHUNKS_4, SEEK_SET);                             write_long(outfile, numdatachunks);                         }                     }                       if (abortflag)                     {                         gui_seterror("Transfer aborted!/n");                     }                 }             }         }         my_closesocket(conn_socket);     }       return abortflag; }    

    最新回复(0)