avi 打包

   1 // avi文件固定大小:1MB = 1048576 Bytes
   2 // 不足的部分置空,最后一帧超过的放弃,并关闭文件。
   3 // 声道只有一个,如果编码速度来得及,就用aac,否则就用pcm。
   4 
   5 #include "stdafx.h"
   6 #include <stdlib.h>
   7 #include <stdio.h>
   8 #include <string.h>    
   9 
  10 #include "DPAVIRecorder.h"
  11 
  12 #define AVI_MAX_LEN 0x400000
  13 
  14 #ifndef MAX_PATH
  15 #define MAX_PATH 256
  16 #endif
  17 
  18 #define AVI_SEEK_SET    0
  19 #define AVI_SEEK_CUR    1
  20 #define AVI_SEEK_END    2
  21 
  22 #define PAD_EVEN(x) ( ((x)+1) & ~1 )
  23 
  24 #define HEADERBYTES 512
  25 #define HEADERMOVISTART (HEADERBYTES-4)
  26 
  27 typedef FILE *avi_hfile;
  28 
  29 //".avi", ".hdrl", ".movi", ".idxl"
  30 #define AVI_POSTFIX_AVI     0
  31 #define AVI_POSTFIX_HDRL    1
  32 #define AVI_POSTFIX_MOVI    2
  33 #define AVI_POSTFIX_IDX1    3   
  34 #define AVI_POSTFIX_MAX     4
  35 
  36  
  37 typedef struct _Chunk
  38 {
  39     avi_int32 ChunkId;              /* Chunk ID marker */
  40     avi_int32 ChunkSize;            /* Size of the chunk data in bytes */
  41     avi_byte  ChunkData[];            /* The chunk data */
  42 } CHUNK, *LPCHUNK;
  43  
  44 /** < Chunk payload ("avih") */
  45 typedef struct _AVIHeader
  46 {
  47     avi_int32 TimeBetweenFrames;     /* Time delay between frames */
  48     avi_int32 MaximumDataRate;       /* Data rate of AVI data */
  49     avi_int32 PaddingGranularity;    /* Size of single unit of padding */
  50     avi_int32 Flags;                 /* Data parameters */
  51     avi_int32 TotalNumberOfFrames;   /* Number of video frame stored */
  52     avi_int32 NumberOfInitialFrames; /* Number of preview frames */
  53     avi_int32 NumberOfStreams;       /* Number of data streams in chunk*/
  54     avi_int32 SuggestedBufferSize;   /* Minimum playback buffer size */
  55     avi_int32 Width;                 /* Width of video frame in pixels */
  56     avi_int32 Height;                /* Height of video frame in pixels*/
  57     avi_int32 TimeScale;             /* Unit used to measure time */
  58     avi_int32 DataRate;              /* Data rate of playback */
  59     avi_int32 StartTime;             /* Starting time of AVI data */
  60     avi_int32 DataLength;            /* Size of AVI data chunk */
  61 } AVIHEADER, *LPAVIHEADER;
  62 
  63 /** < Chunk payload ("strh") */
  64 typedef struct _StreamHeader
  65 {
  66     avi_int32 DataType;                /* Chunk identifier ("vids") */
  67     avi_int32 DataHandler;            /* Device handler identifier ("H264") */
  68     avi_int32 Flags;                 /* Data parameters */
  69     avi_int32 Priority;              /* Set to 0 */
  70     avi_int32 InitialFrames;         /* Number of initial audio frames */
  71     avi_int32 TimeScale;             /* Unit used to measure time */
  72     avi_int32 DataRate;              /* Data rate of playback */
  73     avi_int32 StartTime;             /* Starting time of AVI data */
  74     avi_int32 DataLength;            /* Size of AVI data chunk */
  75     avi_int32 SuggestedBufferSize;   /* Minimum playback buffer size */
  76     avi_int32 Quality;               /* Sample quailty factor */
  77     avi_int32 SampleSize;            /* Size of the sample in bytes */
  78     struct {
  79         avi_int32 left;
  80         avi_int32 top;
  81         avi_int32 right;
  82         avi_int32 bottom;
  83     } rcFrame;
  84 } STREAMHEADER, *LPSTREAMHEADER;
  85 
  86 /** < Chunk payload ("strf") */
  87 typedef struct _BitMapInfoHeader {
  88     avi_int32 biSize;
  89     avi_int32 biWidth;
  90     avi_int32 biHeight;
  91     avi_int16 biPlanes;
  92     avi_int16 biBitCount;
  93     avi_int32 biCompression;
  94     avi_int32 biSizeImage;
  95     avi_int32 biXPelsPerMeter;
  96     avi_int32 biYPelsPerMeter;
  97     avi_int32 biClrUsed;
  98     avi_int32 biClrImportant;
  99 } BITMAPINFOHEADER, *LPBITMAPINFOHEADER;
 100 
 101 /** < Chunk payload ("strf") */
 102 typedef struct _WaveFormatHeader
 103 {
 104     avi_int16 wFormatTag; 
 105     avi_int16 nChannels;         //声道数
 106     avi_int32 nSamplesPerSec;    //采样率
 107     avi_int32 nAvgBytesPerSec;    //WAVE声音中每秒的数据量
 108     avi_int16 nBlockAlign;        //数据块的对齐标志
 109     avi_int16 wBitsPerSample;    //采样的位宽
 110 } WAVEFORMATHEADER, *LPWAVEFORMATHEADER;
 111 
 112 typedef struct _AviIndex
 113 {
 114     avi_int32 Identifier;    /* Chunk identifier reference */
 115     avi_int32 Flags;         /* Type of chunk referenced */
 116     avi_int32 Offset;        /* Position of chunk in file */
 117     avi_int32 Length;        /* Length of chunk in bytes */
 118 } AVIINDEX, *LPAVIINDEX;
 119 
 120 typedef struct _JunkChunk
 121 {
 122     avi_int32 ChunkId;             /* Chunk ID marker (JUNK)*/
 123     avi_int32 PaggingSize;         /* Size of the padding in bytes */
 124     avi_byte Padding[];   /* Padding */
 125 } JUNKCHUNK, *LPJUNKCHUNK;
 126 
 127 typedef struct _AVI_FILE_HANDLE
 128 {
 129     avi_string name;
 130     avi_hfile hdrl;
 131     avi_hfile movi;
 132     avi_hfile idx1;
 133 } output_handles;
 134 
 135 #define MAX_OUTPUT_HANDLE_NUM 4
 136 
 137 typedef struct avi_recorder_handle_st{    
 138     char            dir_path[MAX_PATH];
 139     output_handles    ohandles[MAX_OUTPUT_HANDLE_NUM];
 140     //avi_byte        hdrl_cache[512];
 141     avi_size        hdrl_size;
 142      avi_int32        max_duration; //最大的时长,单位:ms
 143     avi_int32        combine_position; //合并文件后的相对位置
 144     avi_int32        max_frame_bytes; // 最大帧的长度
 145     avi_int32        num_frames; //  
 146     avi_int32        num_audios;
 147     avi_int32       num_chunk; // 当前数据块的个数
 148     avi_int32       num_idx; // 当前索引块的个数
 149     avi_int32        num_streams;
 150 
 151     /** < video param > */
 152     avi_int32        frame_per_sec; 
 153     avi_int32        frame_width;
 154     avi_int32        frame_height;
 155 
 156     /** < audio param > */
 157     avi_int32        sample_per_sec; 
 158     avi_int32        bits_per_sample; 
 159     avi_int32        audio_channels;
 160 
 161     avi_int8        file_name[MAX_OUTPUT_HANDLE_NUM][64];
 162 
 163 } avi_st;
 164 
 165 static avi_fn_alloc g_fn_alloc = NULL;
 166 static avi_fn_realloc g_fn_realloc = NULL;
 167 static avi_fn_free g_fn_free = NULL;
 168 static char *g_file_postfix[] = {".avi", ".hdrl", ".movi", ".idx1"};  
 169 
 170 void dp_avi_set_alloc_func(avi_fn_alloc alloc, avi_fn_realloc realloc, avi_fn_free free)
 171 {       
 172     g_fn_alloc = alloc;
 173     g_fn_realloc = realloc;
 174     g_fn_free = free;
 175 }
 176 
 177 static inline void *avi_alloc(avi_size size)
 178 {
 179     if (g_fn_alloc)
 180         return g_fn_alloc(size);
 181     else
 182         return malloc(size);
 183 }
 184 
 185 
 186 static inline void *avi_realloc(void *ptr, avi_size size)
 187 {
 188     if (g_fn_realloc)
 189         return g_fn_realloc(ptr, size);
 190     else
 191         return realloc(ptr, size);
 192 }
 193 
 194 
 195 static inline void avi_free (void *ptr)
 196 {
 197     if (g_fn_free)
 198         g_fn_free(ptr);
 199     else
 200         free(ptr);
 201 }
 202 
 203 //////////////////////////////////////////////////////////////////////////
 204 
 205 static avi_fn_log g_fn_log_debug = NULL;
 206 static avi_fn_log g_fn_log_error = NULL;
 207 
 208 void dp_avi_set_log_func (avi_fn_log debug, avi_fn_log error)
 209 {
 210     g_fn_log_debug = debug;
 211     g_fn_log_error = error;      
 212 }
 213 
 214 static inline void avi_log_debug (avi_cstring message)
 215 {
 216     if (g_fn_log_debug)
 217         g_fn_log_debug(message);
 218 #ifdef _DEBUG
 219     else
 220         printf("[dbg]%s\r\n",message);
 221 #endif    
 222 }
 223 
 224 
 225 static inline void avi_log_error (avi_cstring message)
 226 {
 227     if (g_fn_log_error)
 228         g_fn_log_error(message);
 229 #ifdef _DEBUG
 230     else
 231         printf("[err]%s\r\n",message);
 232 #endif    
 233 }
 234 
 235 //////////////////////////////////////////////////////////////////////////
 236 
 237 /* Copy n into dst as a 4 byte, little endian number.
 238 Should also work on big endian machines */
 239 
 240 static avi_size avi_ulong2bstr (avi_bptr dst, unsigned long num)
 241 {
 242     dst[0] = 0xff & (num); 
 243     dst[1] = 0xff & (num >> 8); 
 244     dst[2] = 0xff & (num >> 16); 
 245     dst[3] = 0xff & (num >> 24);
 246     return 4;
 247 }
 248 
 249 static avi_size avi_ushort2bstr (avi_bptr dst, unsigned short num)
 250 {
 251     dst[0] = (num) & 0xff; dst[1] = (num >> 8) & 0xff;
 252     return 2;
 253 }
 254 
 255 static avi_size avi_bstr2ulong (unsigned long dst, avi_cbptr str)
 256 {
 257     dst = ( str[0] | (str[1] << 8) | (str[2] << 16) | (str[3] << 24) );
 258     return 4;
 259 }
 260 
 261 static avi_size avi_bstr2ushort (unsigned short dst, avi_cbptr str)
 262 {
 263     dst = ( str[0] | (str[1] << 8) );
 264     return 2;
 265 }
 266 
 267 static avi_size avi_tag2bstr (avi_bptr dst, avi_cstring tag)
 268 {
 269     dst[0] = (avi_byte)(0x7f & tag[0]);
 270     dst[1] = (avi_byte)(0x7f & tag[1]);
 271     dst[2] = (avi_byte)(0x7f & tag[2]);
 272     dst[3] = (avi_byte)(0x7f & tag[3]);
 273     return 4;
 274 }    
 275 
 276 static unsigned long avi_tag2ulong (avi_cstring tag)
 277 {
 278     avi_byte dst[4];
 279     dst[0] = (avi_byte)(0x7f & tag[0]);
 280     dst[1] = (avi_byte)(0x7f & tag[1]);
 281     dst[2] = (avi_byte)(0x7f & tag[2]);
 282     dst[3] = (avi_byte)(0x7f & tag[3]);
 283     return *(unsigned long *)dst;
 284 }
 285 
 286 static avi_size avi_string_merge_path_file_postfix (avi_string dest, 
 287                                              avi_cstring path, 
 288                                              avi_cstring file,
 289                                              avi_cstring postfix,
 290                                              avi_size maxsize)
 291 {                        
 292     char _dest[MAX_PATH] = {0};
 293     avi_size len = strlen(strcpy(_dest, path));
 294     len += strlen(strcpy(_dest + len, "\\"));
 295     len += strlen(strcpy(_dest + len, file));
 296     len += strlen(strcpy(_dest + len, postfix));
 297      
 298     for(avi_size i = 0, j = 0; i < MAX_PATH; i++, j++)
 299     {
 300         if (_dest[j] == '\\')
 301         {
 302             dest[i++] = '\\';
 303         }
 304         dest[i] = _dest[j];
 305         if (_dest[j] == '\0')
 306             return i;
 307     }   
 308     return 0;
 309 }      
 310 
 311 //////////////////////////////////////////////////////////////////////////
 312 
 313 static avi_hfile avi_open_file (avi_cstring file_path)
 314 {       
 315     FILE *fp;                      
 316 
 317     if ((fp = fopen(file_path,"wb+")) == NULL)
 318     {
 319         avi_log_error("avi_write_open: fail to open file!");
 320         return 0;
 321     }
 322     return fp; 
 323 }
 324 static avi_hfile avi_open_existed_file (avi_cstring file_path)
 325 {       
 326     FILE *fp;                      
 327 
 328     if ((fp = fopen(file_path,"rb")) == NULL)
 329     {
 330         avi_log_error("avi_write_open: fail to open file!");
 331         return 0;
 332     }
 333     return fp; 
 334 }
 335 static avi_int32 avi_close_file (avi_hfile hfile)
 336 {
 337     if (hfile)
 338         return fclose(hfile);
 339     else
 340         avi_log_error("avi_close_file: invalid file handle");
 341     return 0;
 342 }
 343 
 344 static avi_size avi_read_file (avi_hfile fd, avi_bptr buf, avi_size len)
 345 {
 346     size_t n = 0;
 347     size_t r = 0;
 348     FILE *fp = (FILE *)fd;
 349 
 350     while (r < len) {
 351         n = fread (buf + r, 1, len - r, fp);
 352 
 353         if ((avi_ssize)n <= 0)
 354             return r;
 355         r += n;
 356     }
 357 
 358     return r;
 359 }
 360 
 361 static avi_size avi_write_file (avi_hfile fd, avi_cbptr buf, avi_size len)
 362 {
 363     size_t n = 0;
 364     size_t r = 0;
 365     FILE *fp = (FILE *)fd;
 366 
 367     while (r < len) {
 368         n = fwrite (buf + r, 1, len - r, fp);
 369         if ((avi_ssize)n < 0)
 370             return n;
 371 
 372         r += n;
 373     }
 374     return r;
 375 }     
 376 
 377 static avi_bool avi_seek_file (avi_hfile fd, avi_int32 offset, avi_int32 fromwhere)
 378 {
 379     size_t n = 0;
 380     size_t r = 0;
 381     FILE *fp = (FILE *)fd;
 382     avi_int32 flag_map[] = { SEEK_SET, SEEK_CUR, SEEK_END };
 383  
 384     if ( fseek (fp, offset, flag_map[fromwhere]) < 0 )
 385     {
 386         avi_log_error("avi_seek_file: move point error");
 387         return avi_false;
 388     }        
 389 
 390     return avi_true;
 391 }      
 392 
 393 
 394 static avi_size avi_tell_file (avi_hfile fd)
 395 {      
 396     return ftell(fd);
 397 }    
 398 
 399 #define AVI_FILE_SIZE (avi_size)(0x100000) // 1 MB = 1048576 Byte
 400 
 401 
 402 static avi_bptr avi_write_chunk(avi_bptr pb, avi_cstring tag, avi_size size)
 403 {
 404     LPCHUNK p = (LPCHUNK)pb;
 405     p->ChunkId = avi_tag2ulong(tag);
 406     p->ChunkSize = size;  
 407     return p->ChunkData;
 408 }    
 409 
 410 static avi_bptr avi_write_chunk_with_data(avi_bptr pb, avi_cstring tag, avi_size size, void *payload, avi_size payload_size)
 411 {     
 412     return ((avi_bptr)memcpy(avi_write_chunk(pb, tag, size), payload, payload_size) + payload_size);
 413 }
 414 
 415 //////////////////////////////////////////////////////////////////////////
 416 
 417 static avi_bptr avi_write_video_avih(avi_bptr pb,
 418                                      avi_int32 frame_per_sec,
 419                                      avi_int32 streams,
 420                                      avi_int32 duration,
 421                                      avi_int32 width, 
 422                                      avi_int32 height)     
 423 {                    
 424     LPAVIHEADER avih;
 425 
 426     avih = (LPAVIHEADER)avi_write_chunk(pb,"avih", sizeof(AVIHEADER)); 
 427     
 428     avih->MaximumDataRate = 400000;
 429     avih->TimeBetweenFrames = 1000000/frame_per_sec;
 430     avih->TotalNumberOfFrames = duration * frame_per_sec; 
 431     avih->NumberOfStreams = streams;
 432     avih->Width = width;
 433     avih->Height = height;
 434 
 435     return (pb + sizeof(AVIHEADER) + sizeof(CHUNK));
 436 }
 437 static avi_bptr avi_write_video_strh_payload(avi_bptr pb, 
 438                                              avi_int32 frame_per_sec, 
 439                                              avi_int32 record_time)
 440 {
 441     /** < CHUNK - strh - payload */
 442 
 443     LPSTREAMHEADER payload = (LPSTREAMHEADER)pb;
 444 
 445     payload->DataType = avi_tag2ulong("vids");
 446     payload->DataHandler = avi_tag2ulong("H264");
 447     payload->TimeScale = 1000000/frame_per_sec;
 448     payload->DataRate = 1000000;
 449     payload->DataLength = frame_per_sec * record_time;
 450 
 451     return (pb + sizeof(STREAMHEADER));
 452 }
 453 
 454 static avi_bptr avi_write_video_strf_payload(avi_bptr pb, avi_int32 width, avi_int32 height)
 455 {
 456     /** < CHUNK - strf - payload */
 457 
 458     LPBITMAPINFOHEADER payload = (LPBITMAPINFOHEADER)pb;
 459 
 460     payload->biSize = sizeof(BITMAPINFOHEADER);
 461     payload->biWidth = width;
 462     payload->biHeight = height;
 463     payload->biPlanes = 1;
 464     payload->biBitCount = 24;
 465     payload->biCompression = avi_tag2ulong("H264");
 466     payload->biSizeImage = width * height;
 467 
 468     return (pb + sizeof(BITMAPINFOHEADER));
 469 }
 470 
 471 static avi_bptr avi_write_video_strl(avi_bptr pb, 
 472                                      avi_int32 frame_rate, 
 473                                      avi_int32 width, 
 474                                      avi_int32 height,
 475                                      avi_int32 max_duration)
 476 {     
 477     avi_bptr wt_ptr; 
 478     avi_int32 tlen = sizeof(STREAMHEADER) + sizeof(BITMAPINFOHEADER) + 8*2 + 4;
 479     wt_ptr = avi_write_chunk_with_data(pb,"LIST", tlen, "strl", 4); 
 480 
 481     wt_ptr = avi_write_chunk(wt_ptr, "strh", sizeof(STREAMHEADER));
 482     wt_ptr = avi_write_video_strh_payload(wt_ptr, frame_rate, max_duration);
 483 
 484     wt_ptr = avi_write_chunk(wt_ptr, "strf", sizeof(BITMAPINFOHEADER));
 485     wt_ptr = avi_write_video_strf_payload(wt_ptr, width, height);
 486 
 487     return wt_ptr;    
 488 }
 489 
 490 
 491 static avi_bptr avi_write_audio_strh_payload(avi_bptr pb, 
 492                                              avi_int32 sample_per_sec, 
 493                                              avi_int32 bits_per_sample, 
 494                                              avi_int32 channels, 
 495                                              avi_int32 max_duration)
 496 {
 497     /** < CHUNK - strh - payload */
 498 
 499     LPSTREAMHEADER payload = (LPSTREAMHEADER)pb;
 500 
 501     payload->DataType = avi_tag2ulong("auds");
 502     //payload->DataHandler = avi_tag2ulong("H264");
 503     payload->TimeScale = (bits_per_sample >> 3) * channels;
 504     payload->DataRate = payload->TimeScale * sample_per_sec;
 505     payload->DataLength = sample_per_sec * max_duration;
 506     payload->SampleSize = (bits_per_sample >> 3) * channels; 
 507     return (pb + sizeof(STREAMHEADER));
 508 }
 509 
 510 
 511 static avi_bptr avi_write_audio_strf_payload(avi_bptr pb, 
 512                                              avi_int32 sample_per_sec, 
 513                                              avi_int32 bits_per_sample, 
 514                                              avi_int32 channels)
 515 {
 516     /** < CHUNK - strf - payload */
 517 
 518     LPWAVEFORMATHEADER payload = (LPWAVEFORMATHEADER)pb;
 519 
 520     payload->wFormatTag = 1;
 521     payload->nChannels = channels;
 522     payload->nSamplesPerSec = sample_per_sec;
 523     payload->nAvgBytesPerSec = sample_per_sec * channels * (bits_per_sample >> 3);
 524     payload->nBlockAlign = channels * (bits_per_sample >> 3);    
 525     payload->wBitsPerSample = bits_per_sample;    
 526 
 527     return (pb + sizeof(WAVEFORMATHEADER));
 528 }
 529 
 530 static avi_bptr avi_write_audio_strl(avi_bptr pb, 
 531                                      avi_int32 sample_per_sec, // 8000
 532                                      avi_int32 bits_per_sample,    // 16bit
 533                                      avi_int32 channels,  // 2    
 534                                      avi_int32 record_time)  
 535 {    
 536     avi_bptr wt_ptr; 
 537     avi_int32 tlen = sizeof(STREAMHEADER) + sizeof(WAVEFORMATHEADER) + 8*2 + 4;
 538     wt_ptr = avi_write_chunk_with_data (pb,"LIST", tlen, "strl", 4); 
 539 
 540     wt_ptr = avi_write_chunk (wt_ptr, "strh", sizeof(STREAMHEADER));
 541     wt_ptr = avi_write_audio_strh_payload (wt_ptr, sample_per_sec, bits_per_sample, channels, record_time);
 542 
 543     wt_ptr = avi_write_chunk (wt_ptr, "strf", sizeof(WAVEFORMATHEADER));
 544     wt_ptr = avi_write_audio_strf_payload (wt_ptr, sample_per_sec, bits_per_sample, channels);
 545 
 546     return wt_ptr;    
 547 }
 548 
 549  
 550 static avi_size avi_write_hdrl(avi_st *pst, avi_bptr buff)
 551 {
 552     avi_bptr pb = buff;      
 553 //#ifdef _DEBUG
 554 //    pb = avi_write_chunk_with_data (pb, "RIFF", 512, "AVI ", 4);
 555 //#endif
 556     pb = avi_write_chunk_with_data (pb,"LIST", 308, "hdrl", 4); 
 557     pb = avi_write_video_avih (pb, pst->frame_per_sec, pst->num_streams,    pst->max_duration, pst->frame_width, pst->frame_height);  
 558     pb = avi_write_video_strl (pb, pst->frame_per_sec, pst->frame_width, pst->frame_height, pst->max_duration);
 559     pb = avi_write_audio_strl (pb, pst->sample_per_sec,pst->bits_per_sample, pst->audio_channels, pst->max_duration);
 560     pb = avi_write_chunk_with_data (pb,"JUNK", HEADERBYTES - 308 - 40, "hdrl", 4);                                  
 561     return (pb - buff);     
 562 }
 563 
 564 //////////////////////////////////////////////////////////////////////////
 565 
 566 
 567 /* Add a chunk (=tag and data) to the AVI file,
 568 returns -1 on write error, 0 on success */
 569 
 570 static avi_bool avi_add_chunk(avi_hfile fd, avi_cstring tag, avi_cbptr data, avi_size length)
 571 {
 572     avi_byte buff[8] = {0};
 573     LPCHUNK pchunk = (LPCHUNK)buff;
 574 
 575     avi_size pos = avi_tell_file(fd);
 576 
 577     /* Copy tag and length int c, so that we need only 1 write system call
 578     for these two values */
 579 
 580     pchunk->ChunkId = avi_tag2ulong(tag);
 581     pchunk->ChunkSize = length;     
 582 
 583     /* Output tag, length and data, restore previous position
 584     if the write fails */
 585 
 586     length = PAD_EVEN(length);
 587 
 588     if (avi_write_file(fd, buff, 8) != 8 || avi_write_file(fd, data, length) != length) {
 589         avi_seek_file (fd, pos, AVI_SEEK_SET);
 590         avi_log_error ("avi_add_chunk: write error");
 591         return avi_false;
 592     }
 593  
 594     return avi_true;
 595 }
 596 
 597 static avi_bool avi_add_index_entry(avi_hfile fd, avi_cstring tag, long flags, long pos, long len)
 598 {
 599     avi_size wlen;
 600     AVIINDEX _index;       
 601 
 602     /* Add index entry */
 603     
 604     _index.Identifier = avi_tag2ulong(tag);
 605     _index.Flags = flags;
 606     _index.Offset = pos - HEADERMOVISTART;
 607     _index.Length = len;
 608  
 609     if (avi_write_file(fd, (avi_cbptr)&_index, sizeof(AVIINDEX)) == 0)
 610     {
 611         avi_log_error ("avi_add_index_entry: write file error");
 612         return avi_false;
 613     }
 614  
 615     return avi_true;
 616 }
 617 
 618 static avi_bool avi_write_data(avi_st *pst, avi_int32 index, avi_cbptr data, avi_size length, avi_int32 is_video)
 619 {
 620     int n;
 621     avi_size len;
 622     avi_hfile idx1, movi;
 623 
 624     idx1 = pst->ohandles[index].idx1;
 625     movi = pst->ohandles[index].movi;
 626 
 627     /* Check for maximum file length */
 628 
 629     if ( (pst->combine_position + 8 + length + 8 + (pst->num_idx + 1) * 16) > AVI_MAX_LEN ) {
 630         avi_log_error("exceed the file size limit");
 631         return avi_false;
 632     }
 633 
 634     /* Add index entry */
 635 
 636     if (!is_video)
 637         n = avi_add_index_entry(idx1, "01wb", 0x00, pst->combine_position, length);
 638     else    if (is_video == 1) // 非压缩帧
 639         n = avi_add_index_entry(idx1, "00db", 0x10, pst->combine_position, length);
 640     else    if (is_video == 2) // 压缩帧
 641         n = avi_add_index_entry(idx1, "00dc", 0x10, pst->combine_position, length);
 642 
 643     if (!n) return avi_false;
 644 
 645     pst->combine_position += 8 + length;
 646 
 647     /* Output tag and data */
 648 
 649     if (!is_video)
 650         len = avi_add_chunk(movi, "01wb", data, length);
 651     else    if (is_video == 1) // 非压缩帧
 652         len = avi_add_chunk(movi, "00db", data, length);
 653     else    if (is_video == 2) // 压缩帧
 654         len = avi_add_chunk(movi, "00dc", data, length);
 655 
 656     if (!len) return avi_false;
 657 
 658     pst->combine_position += 16;
 659 
 660     return avi_true;
 661 }
 662 
 663 static avi_bool avi_write_frame(avi_st *pst, avi_int32 index, avi_cbptr data, avi_size bytes, avi_bool is_iframe)
 664 {         
 665     if ( avi_write_data(pst, index, data, bytes, is_iframe ? 1 : 2) ) 
 666         return avi_false;
 667 
 668     pst->combine_position += bytes;    
 669     pst->num_frames++;
 670 
 671     if (pst->max_frame_bytes < bytes)
 672         pst->max_frame_bytes = bytes;
 673  
 674    return avi_true;
 675 }
 676 
 677 static avi_bool avi_write_audio(avi_st *pst, avi_int32 index, avi_cbptr data, avi_size len)
 678 {      
 679     if ( avi_write_data(pst, index, data, len, 0) ) 
 680         return avi_false;
 681   
 682     pst->num_audios++;
 683     return avi_true;
 684 }
 685 
 686 avi_bool avi_set_video(avi_st * pst, avi_int32 width, avi_int32 height, avi_int32 fps)
 687 {
 688     if (!(((width == 352) && (height == 288)) 
 689         || ((width == 640) && (height == 480))
 690         || ((width == 1024) && (height == 600))
 691         || ((width == 1024) && (height == 720))))
 692         return avi_false;
 693  
 694     if (!((fps >= 10) && (fps <= 30)))
 695         return avi_false;
 696 
 697     pst->frame_width = width;
 698     pst->frame_height = height;
 699     pst->frame_per_sec = fps;  
 700    return avi_true;
 701 }
 702 
 703 avi_bool avi_set_audio(avi_st * pst, 
 704                        avi_int32 channels, 
 705                        avi_int32 sample_per_sec, 
 706                        avi_int32 bits_per_sample)
 707 {
 708     if ((channels != 1)    && (channels != 2))
 709         return avi_false;
 710 
 711     if ((sample_per_sec != 8000) 
 712         && (sample_per_sec != 16000) 
 713         && (sample_per_sec != 44100)
 714         && (sample_per_sec != 48000))
 715         return avi_false;
 716 
 717     if ((bits_per_sample != 8) 
 718         && (bits_per_sample != 16) 
 719         && (bits_per_sample != 32))
 720         return avi_false; 
 721     
 722     pst->audio_channels = channels;
 723     pst->sample_per_sec = sample_per_sec;
 724     pst->bits_per_sample = bits_per_sample;
 725 
 726     return avi_true;
 727 }
 728 
 729 avi_bool avi_set_max_duration(avi_st * pst, avi_int32 duration)
 730 {
 731     if ((duration <= 30) || (duration >= 60000))
 732         return avi_false;
 733                              
 734     pst->max_duration = duration;    
 735 
 736     return avi_true;
 737 }
 738 
 739 avi_int32 avi_bytes_remain(avi_st * pst)
 740 {
 741      return 0;
 742 }
 743 
 744 //////////////////////////////////////////////////////////////////////////
 745 
 746 static avi_st *avi_init(avi_cstring savedir)
 747 {
 748     avi_st *pst = NULL;
 749 
 750     if (NULL == savedir)
 751     {
 752         avi_log_error("rbuff_init::save dir is invalid");
 753         return NULL;
 754     }
 755     pst = (avi_st *)avi_alloc(sizeof(avi_st));
 756     if (!pst)
 757     {
 758         avi_log_error("rbuff_init::alloc failed");
 759         return NULL;
 760     }
 761 
 762     memset(pst, 0, sizeof(avi_st));
 763 
 764     strcpy(pst->dir_path, savedir);
 765 
 766     pst->frame_per_sec = 15;
 767     pst->frame_width = 640;
 768     pst->frame_height = 480;
 769     pst->max_duration = 30;
 770     pst->num_streams = 1;
 771 
 772     avi_log_debug("avird_init ok");
 773     return pst;
 774 }     
 775 
 776 static avi_bool avi_combine_file(avi_st * pst, avi_int32 index)
 777 {
 778     /** < open avi file > */
 779     char path[MAX_PATH] = {0}; 
 780     avi_hfile fh_avi, fh_hdrl, fh_movi, fh_idxl;
 781 
 782     if (!pst->ohandles[index].name)
 783          return avi_false;
 784 
 785     avi_string_merge_path_file_postfix(path, 
 786         pst->dir_path, 
 787         pst->ohandles[index].name, 
 788         g_file_postfix[AVI_POSTFIX_AVI], 
 789         MAX_PATH);
 790 
 791     if ((fh_avi = avi_open_file(path)) == NULL)
 792     {    
 793         avi_log_error("avi_release: open avi failed");
 794         return avi_false;
 795     } 
 796 
 797     avi_string_merge_path_file_postfix(path, 
 798         pst->dir_path, 
 799         pst->ohandles[index].name, 
 800         g_file_postfix[AVI_POSTFIX_HDRL], 
 801         MAX_PATH);
 802 
 803     if ((fh_hdrl = avi_open_existed_file(path)) == NULL)
 804     {    
 805         avi_log_error("avi_release: open hdrl failed");
 806         return avi_false;
 807     } 
 808 
 809     avi_string_merge_path_file_postfix(path, 
 810         pst->dir_path, 
 811         pst->ohandles[index].name, 
 812         g_file_postfix[AVI_POSTFIX_MOVI], 
 813         MAX_PATH);
 814 
 815     if ((fh_movi = avi_open_existed_file(path)) == NULL)
 816     {    
 817         avi_log_error("avi_release: open movi failed");
 818         return avi_false;
 819     } 
 820 
 821     avi_string_merge_path_file_postfix(path, 
 822         pst->dir_path, 
 823         pst->ohandles[index].name, 
 824         g_file_postfix[AVI_POSTFIX_IDX1], 
 825         MAX_PATH);
 826 
 827     if ((fh_idxl = avi_open_existed_file(path)) == NULL)
 828     {    
 829         avi_log_error("avi_release: open idxl failed");
 830         return avi_false;
 831     } 
 832 
 833     //////////////////////////////////////////////////////////////////////////
 834 
 835     avi_byte buffer[HEADERBYTES] = {0};
 836     avi_int32 tlen, flen = 0;
 837 
 838     avi_write_chunk_with_data (buffer, "RIFF", 512, "AVI ", 4);
 839     
 840     avi_seek_file (fh_hdrl, 0, AVI_SEEK_END);
 841     tlen = avi_tell_file (fh_hdrl);
 842     avi_seek_file (fh_hdrl, 0, AVI_SEEK_SET);
 843     avi_read_file (fh_hdrl, buffer + 12,  (tlen-12 < HEADERBYTES)?(tlen-12):HEADERBYTES); 
 844     avi_write_file (fh_avi, buffer, tlen - 12); 
 845     avi_close_file(fh_hdrl);
 846     flen += HEADERBYTES;
 847 
 848     //////////////////////////////////////////////////////////////////////////
 849     avi_int32 rlen;     
 850     avi_seek_file (fh_movi, 0, AVI_SEEK_END);
 851     flen += tlen = avi_tell_file (fh_movi);    
 852     avi_write_chunk_with_data (buffer, "LIST", tlen+4, "movi", 4);
 853     avi_write_file (fh_avi, buffer, 12);
 854     avi_seek_file (fh_movi, 0, AVI_SEEK_SET);
 855     while (tlen)
 856     {
 857         rlen = avi_read_file (fh_movi, buffer, HEADERBYTES);
 858         if (rlen == 0)
 859             break;
 860 
 861         avi_write_file (fh_avi, buffer, rlen);
 862         tlen -= rlen;
 863     }
 864     avi_close_file(fh_movi);
 865     //flen += tlen;
 866 
 867     //////////////////////////////////////////////////////////////////////////
 868     avi_seek_file (fh_idxl, 0, AVI_SEEK_END);
 869     flen += tlen = avi_tell_file (fh_idxl);
 870     avi_write_chunk (buffer, "idx1", tlen);
 871     avi_write_file (fh_avi, buffer, 8);
 872     avi_seek_file (fh_idxl, 0, AVI_SEEK_SET);
 873     while (tlen)
 874     {
 875         rlen = avi_read_file (fh_idxl, buffer, HEADERBYTES);
 876         if (rlen == 0)
 877             break;
 878 
 879         avi_write_file (fh_avi, buffer, rlen);     
 880         tlen -= rlen;
 881     }
 882     avi_close_file(fh_idxl);
 883     //flen += tlen;
 884     
 885     avi_seek_file (fh_avi, 0, AVI_SEEK_SET);
 886     avi_write_chunk_with_data (buffer, "RIFF", flen, "AVI ", 4);
 887     avi_write_file (fh_avi, buffer, 12);
 888 
 889     avi_close_file(fh_avi);
 890 }
 891 
 892 static avi_bool avi_release(avi_st * pst)
 893 {
 894     if (pst)
 895     {
 896         for (avi_size i = 0; i< MAX_OUTPUT_HANDLE_NUM; i++)
 897         {    
 898              avi_combine_file(pst, i);
 899         }
 900 
 901         free(pst);
 902     }
 903     avi_log_debug("avi_release ok");
 904 
 905     return avi_true;
 906 }
 907 
 908 static avi_int32 avi_get_free_ohandle(avi_st *pst, avi_string name)
 909 {
 910     avi_uint32 idx;
 911 
 912     for (idx = 0; idx < 4; idx++)
 913     {
 914         avi_string str = pst->ohandles[idx].name;
 915 
 916         if ( str && strlen(str) > 0)
 917         {
 918             continue;
 919         }
 920         memset (&pst->ohandles[idx], 0, sizeof(output_handles));
 921         pst->ohandles[idx].name = name;
 922         return idx;
 923     }
 924     return -1;
 925 }
 926 
 927 static avi_bool avi_open_output_file(avi_st *pst, avi_cstring name, avi_int32ptr index)
 928 {       
 929     avi_hfile fh;
 930     char path[MAX_PATH] = {0}; 
 931     avi_int32 idx;
 932 
 933     if ( (idx = avi_get_free_ohandle(pst, name)) < 0)
 934         return avi_false;
 935 
 936     pst->combine_position = HEADERBYTES;
 937 
 938     /** < open hdrl file > */
 939     avi_string_merge_path_file_postfix(path , pst->dir_path, name, 
 940                         g_file_postfix[AVI_POSTFIX_HDRL], MAX_PATH);
 941  
 942     if ((fh = avi_open_file(path)) == NULL)
 943     {     
 944         avi_log_error("avi_open_output_file: open hdrl failed");
 945         return avi_false;
 946     }
 947 
 948     avi_byte buffer[HEADERBYTES] = {0};
 949 
 950     avi_write_hdrl(pst, buffer);
 951 
 952     avi_write_file(fh, buffer, HEADERBYTES);
 953 
 954     avi_close_file(fh);
 955              
 956     /** < open index file > */
 957     avi_string_merge_path_file_postfix(path , pst->dir_path, name, 
 958         g_file_postfix[AVI_POSTFIX_IDX1], MAX_PATH);
 959 
 960     if ((fh = avi_open_file(path)) == NULL)
 961     {    
 962         avi_log_error("avi_open_output_file: open index failed");
 963         return avi_false;
 964     }    
 965 
 966     pst->ohandles[idx].idx1 = fh;
 967 
 968     /** < open movi file > */
 969     avi_string_merge_path_file_postfix(path , pst->dir_path, name, 
 970         g_file_postfix[AVI_POSTFIX_MOVI], MAX_PATH);
 971 
 972     if ((fh = avi_open_file(path)) == NULL)
 973     {    
 974         avi_log_error("avi_open_output_file: open movi failed");
 975         return avi_false;
 976     } 
 977 
 978     pst->ohandles[idx].movi = fh;
 979                   
 980     *index = idx;
 981     return avi_true; 
 982 }    
 983 
 984 avi_bool avi_close_output_file(avi_st * pst, avi_int32 index)
 985 {     
 986     if (pst->ohandles[index].name != NULL)
 987     {
 988         avi_close_file(pst->ohandles[index].movi); 
 989         avi_close_file(pst->ohandles[index].idx1);
 990         return avi_false;
 991     }
 992 
 993     return avi_true;   
 994 }
 995 
 996 
 997 //////////////////////////////////////////////////////////////////////////
 998 
 999 avi_handle dp_avi_init(avi_string savedir)
1000 {
1001     return avi_init(savedir);
1002 }
1003 
1004 avi_bool dp_avi_release(avi_handle handle)
1005 {
1006     return avi_release((avi_st *)handle); 
1007 }
1008 
1009 avi_bool dp_avi_open_file(avi_handle handle, avi_string file_name, avi_int32 mode, avi_int32ptr index)
1010 {
1011     if (mode == AVI_MODE_WRITE)
1012         return avi_open_output_file((avi_st *)handle, file_name, index)?avi_true:avi_false;
1013     else
1014         return avi_false;
1015 }
1016 
1017 avi_bool dp_avi_close_output_file(avi_handle handle, avi_int32 index)
1018 {
1019     return avi_close_output_file((avi_st *)handle, index);
1020 }
1021 
1022 avi_bool dp_avi_write_frame(avi_handle handle, avi_int32 index, avi_cbptr frame_data, avi_size bytes, avi_bool is_iframe)
1023 {
1024     return avi_write_frame((avi_st *)handle, index, frame_data, bytes, is_iframe);
1025 }
1026 
1027 avi_bool dp_avi_write_audio(avi_handle handle, avi_int32 index, avi_cbptr audio_data, avi_size bytes)
1028 {
1029     return avi_write_audio((avi_st *)handle, index, audio_data, bytes);
1030 }
1031 
1032 avi_bool dp_avi_set_output_frame(avi_handle handle, avi_int32 width, avi_int32 height, avi_int32 fps)
1033 {
1034     return avi_set_video((avi_st *)handle, width, height, fps);      
1035 }
1036 
1037 avi_bool dp_avi_set_output_audio(avi_handle handle, avi_int32 channels, avi_int32 sample_per_sec, avi_int32 bits_per_sample)
1038 {
1039     return avi_set_audio((avi_st *)handle, channels, sample_per_sec, bits_per_sample);
1040 }
1041 
1042 avi_bool dp_avi_set_output_max_duration(avi_handle handle, avi_int32 duration)
1043 {
1044     return avi_set_max_duration((avi_st *)handle, duration);
1045 }      
1046 
1047 avi_int32 dp_avi_bytes_remain(avi_handle handle)
1048 {
1049     return avi_bytes_remain((avi_st *)handle);
1050 }       

 

测试代码:

int _tmain(int argc, _TCHAR* argv[])
{
    avi_bool ret;
    avi_handle handle;
    avi_int32 index;

    handle = dp_avi_init("D:\\Output");

    dp_avi_set_output_frame(handle, 1024,720,30);

    dp_avi_set_output_audio(handle, 2, 44100, 16);

    dp_avi_set_output_max_duration(handle, 30);

    ret = dp_avi_open_file(handle, "output1", AVI_MODE_WRITE,&index);

    if (ret)
    {
           dp_avi_write_frame(handle, index, (avi_cbptr)("\x01\x02\x03\x04\x05\x06\x07\x08\x09"), 9, 1);

        dp_avi_write_audio(handle, index, (avi_cbptr)("\x01\x02\x03\x04\x05\x06\x07\x08\x09"), 9);

        dp_avi_close_output_file(handle, index);
    }

    dp_avi_release(handle);
       
    return 0;

}

 

关键点:

1、需要写avi文件之前设置文件的时长。

2、同时生成*.movi、*.hdrl、*.idx1 3个文件,分别保存音视频数据,avi格式和索引表。

3、最后,在释放的时候,将上面3个文件合并成一个文件,原因是hdrl文件除了时长,其他信息都是固定的。

      而movi文件会不停添加音视频数据,更新频繁;而idx1文件可以记录关键索引和非关键索引,可以配置。

4、尽量排除与平台相关的实现代码。

 

posted @ 2020-09-19 09:16  joyce3800  阅读(376)  评论(0)    收藏  举报