mpeg4_file.cpp
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:10k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is MPEG4IP.
  13.  * 
  14.  * The Initial Developer of the Original Code is Cisco Systems Inc.
  15.  * Portions created by Cisco Systems Inc. are
  16.  * Copyright (C) Cisco Systems Inc. 2000, 2001.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  *              Bill May        wmay@cisco.com
  20.  */
  21. /*
  22.  * mpeg4_file.cpp
  23.  * Create media structures for session for an mp4v file (raw mpeg4)
  24.  */
  25. #include "mpeg4.h"
  26. #include "type/typeapi.h"
  27. #include "sys/mode.hpp"
  28. #include "sys/vopses.hpp"
  29. //#include "sys/tps_enhcbuf.hpp"
  30. //#include "sys/decoder/enhcbufdec.hpp"
  31. #include "tools/entropy/bitstrm.hpp"
  32. #include "sys/decoder/vopsedec.hpp"
  33. #define logit divx->m_vft->log_msg
  34. /*
  35.  * divx_find_header
  36.  * Search buffer to find the next start code
  37.  */
  38. static int divx_find_header (iso_decode_t *divx,
  39.      uint32_t start_offset)
  40. {
  41.   for (uint32_t ix = start_offset; ix + 4 < divx->m_buffer_size; ix++) {
  42.     if ((divx->m_buffer[ix] == 0) &&
  43. (divx->m_buffer[ix + 1] == 0) &&
  44. (divx->m_buffer[ix + 2] == 1)) {
  45.       return ix;
  46.     }
  47.   }
  48.   return -1;
  49. }
  50. /*
  51.  * divx_reset_buffer
  52.  * Move end of buffer to beginning, fill in rest of buffer
  53.  */
  54. static int divx_reset_buffer (iso_decode_t *divx)
  55. {      
  56.   uint32_t diff, read;
  57.   if (divx->m_buffer_size > divx->m_buffer_on) {
  58.     diff = divx->m_buffer_size - divx->m_buffer_on;
  59.     memmove(divx->m_buffer,
  60.     &divx->m_buffer[divx->m_buffer_on],
  61.     diff);
  62.   } else diff = 0;
  63.   divx->m_buffer_size = diff;
  64.   read = fread(divx->m_buffer + diff, 
  65.        1, 
  66.        divx->m_buffer_size_max - diff,
  67.        divx->m_ifile);
  68.   divx->m_buffer_on = 0;
  69.   if (read <= 0) {
  70.     if (divx->m_buffer_size < 4) divx->m_buffer_size = 0;
  71.     return -1;
  72.   }
  73.   divx->m_buffer_size += read;
  74.   if (divx->m_buffer_size < 4) {
  75.     divx->m_buffer_size = 0;
  76.     return -1;
  77.   }
  78.   return diff;
  79. }
  80. /*
  81.  * divx_buffer_load
  82.  * Make sure we have at least 1 full VOP frame in the buffer
  83.  */
  84. static int divx_buffer_load (iso_decode_t *divx, uint8_t *ftype) 
  85. {
  86.   int next_hdr, left, value;
  87.   if (divx->m_buffer_on + 3 >= divx->m_buffer_size) {
  88.     if (divx_reset_buffer(divx) < 0) return -1;
  89.   }
  90.   next_hdr = divx_find_header(divx, divx->m_buffer_on);
  91.   if (next_hdr < 0) return -1;
  92.   // We've got the first header pointed to by m_buffer_on
  93.   divx->m_buffer_on = next_hdr;
  94.   // Is it a VOP header ?  If not, find the first VOP header
  95.   if (divx->m_buffer[next_hdr + 3] != 0xb6) {
  96.     value = 0;
  97.     do {
  98.       // Increment when we've got a header pointed to by next_hdr
  99.       if (value >= 0) next_hdr += 4;
  100.       value = divx_find_header(divx, next_hdr);
  101.       if (value < 0) {
  102. if (divx->m_buffer_on == 0 &&
  103.   divx->m_buffer_size == divx->m_buffer_size_max) {
  104.   // weirdness has happened.  We've got a full buffer of
  105.   // headers, no frames
  106.   return -1;
  107. }
  108. left = divx_reset_buffer(divx);
  109. if (left < 0) {
  110.   // No more new data - we've reached the end... 
  111.   return divx->m_buffer_size;
  112. }
  113. // okay - this case is gross - we'll start checking from the
  114. // beginning
  115. next_hdr = left - 4;
  116.       } else {
  117. next_hdr = value;
  118.       }
  119.     } while (value < 0 || divx->m_buffer[next_hdr + 3] != 0xb6);
  120.   }
  121.   // next_hdr contains the location of the first VOP.
  122.   // Record the file type (top 2 bits) after 00 00 01 b6
  123.   *ftype = divx->m_buffer[next_hdr + 4];
  124.   // Find the next header.
  125.   value = divx_find_header(divx, next_hdr + 4);
  126.   if (value >= 0) {
  127.     // Cool - it's in the header...
  128.     return value;
  129.   }
  130.   //
  131.   // Not in the header - reset the buffer, then continue search
  132.   //
  133.   value = divx->m_buffer_size - divx->m_buffer_on;
  134.   left = divx_reset_buffer(divx);
  135.   if (left < 0) return divx->m_buffer_size;
  136.   value = divx_find_header(divx, value);
  137.   if (value >= 0) {
  138.     return value;
  139.   }
  140.   // We don't have enough read in... Go forward
  141.   while (divx->m_buffer_size_max < 65535) {
  142.     int old, readsize;
  143.     divx->m_buffer = (uint8_t *)realloc(divx->m_buffer,
  144. divx->m_buffer_size_max + 1024);
  145.     readsize = fread(&divx->m_buffer[divx->m_buffer_size_max],
  146.      1, 
  147.      1024, 
  148.      divx->m_ifile);
  149.     if (readsize <= 0) {
  150.       return (divx->m_buffer_size - divx->m_buffer_on);
  151.     }
  152.     old = divx->m_buffer_size;
  153.     divx->m_buffer_size += readsize;
  154.     divx->m_buffer_size_max += 1024;
  155.     value = divx_find_header(divx, old - 4);
  156.     if (value >= 0) return value;
  157.   }
  158.   return -1;
  159. }
  160. /*
  161.  * divx_file_check
  162.  * Check the file.  If it's a .divx file, look for the VOL, and record
  163.  * where the I frames are.
  164.  */
  165. codec_data_t *mpeg4_iso_file_check (lib_message_func_t message,
  166.     const char *name, 
  167.     double *max,
  168.     char *desc[4])
  169. {
  170.   int len;
  171.   iso_decode_t *iso;
  172.   uint32_t framecount = 0;
  173.   uint64_t calc;
  174.   /*
  175.    * Compare with .divx extension
  176.    */
  177.   len = strlen(name);
  178.   if ((strcasecmp(name + len - 5, ".divx") != 0) &&
  179.       (strcasecmp(name + len - 5, ".mp4v") != 0) &&
  180.       (strcasecmp(name + len - 4, ".cmp") != 0)) {
  181.     return NULL;
  182.   }
  183.   /*
  184.    * Malloc the divx structure, init some variables
  185.    */
  186.   iso = MALLOC_STRUCTURE(iso_decode_t);
  187.   memset(iso, 0, sizeof(*iso));
  188.   iso->m_main_short_video_header = FALSE;
  189.   iso->m_pvodec = new CVideoObjectDecoder();
  190.   iso->m_decodeState = DECODE_STATE_VOL_SEARCH;
  191.   iso->m_ifile = fopen(name, FOPEN_READ_BINARY);
  192.   if (iso->m_ifile == NULL) {
  193.     free(iso);
  194.     return NULL;
  195.   }
  196.   iso->m_buffer = (uint8_t *)malloc(16 * 1024);
  197.   iso->m_buffer_size_max = 16 * 1024;
  198.   iso->m_fpos = new CFilePosRecorder();
  199.   iso->m_fpos->record_point(0, 0, 0);
  200.   /*
  201.    * Start searching the file, find the VOL, mark the I frames
  202.    */
  203.   int havevol = 0;
  204.   int nextframe;
  205.   uint8_t ftype;
  206.   nextframe = divx_buffer_load(iso, &ftype);
  207.   do {
  208.     if (havevol == 0) {
  209.       iso->m_pvodec->SetUpBitstreamBuffer((unsigned char *)&iso->m_buffer[iso->m_buffer_on],
  210.   iso->m_buffer_size - iso->m_buffer_on);
  211.       try {
  212. iso->m_pvodec->decodeVOLHead();
  213. havevol = 1;
  214. iso->m_buffer_on = nextframe;
  215. iso->m_framerate = iso->m_pvodec->getClockRate();
  216. message(LOG_DEBUG, "mp4iso", "Found vol in mpeg4 file clock rate %d",
  217. iso->m_framerate);
  218.       } catch (...) {
  219. iso->m_buffer_on += iso->m_pvodec->get_used_bytes();
  220. //iso->m_buffer_on = iso->m_buffer_size - 3;
  221.       }
  222.     } else {
  223.       // If we have an I_VOP, mark it.
  224.       if ((ftype & 0xc0) == 0) {
  225. calc = framecount * 1000;
  226. calc /= iso->m_framerate;
  227. //message(LOG_DEBUG, "mp4iso", "I frame at %u "LLU, framecount, calc);
  228. iso->m_fpos->record_point(ftell(iso->m_ifile) - 
  229.   iso->m_buffer_size - 
  230.   iso->m_buffer_on, 
  231.   calc, 
  232.   framecount);
  233.       }
  234.       iso->m_buffer_on = nextframe;
  235.     }
  236.     framecount++;
  237.     nextframe = divx_buffer_load(iso, &ftype);
  238.   } while (nextframe != -1);
  239.   if (havevol == 0) {
  240.     iso_clean_up(iso);
  241.     return NULL;
  242.   }
  243.   if (iso->m_framerate < 0 || iso->m_framerate > 60) iso->m_framerate = 30;
  244.   *max = (double)framecount / (double)iso->m_framerate;
  245.   rewind(iso->m_ifile);
  246.   return ((codec_data_t *)iso);
  247. }
  248. /*
  249.  * divx_file_next_frame
  250.  * Read in the next frame, return timestamp
  251.  */
  252. int divx_file_next_frame (codec_data_t *your_data,
  253.   uint8_t **buffer, 
  254.   uint64_t *ts)
  255. {
  256.   iso_decode_t *divx;
  257.   int next_hdr, value;
  258.   divx = (iso_decode_t *)your_data;
  259.   // start at the next header
  260.   next_hdr = divx_find_header(divx, divx->m_buffer_on);
  261.   if (next_hdr < 0) {
  262.     next_hdr = divx_reset_buffer(divx);
  263.     if (next_hdr < 0) {
  264.       return 0;
  265.     }
  266.     next_hdr = divx_find_header(divx, next_hdr);
  267.     if (next_hdr < 0) {
  268.       return 0;
  269.     }
  270.   }
  271.   divx->m_buffer_on = next_hdr;
  272.   value = 0;
  273.   // find first vop
  274.   while (divx->m_buffer[next_hdr + 3] != 0xb6) {
  275.     value = divx_find_header(divx, next_hdr + 4);
  276.     if (value < 0) {
  277.       value = divx_reset_buffer(divx);
  278.       if (value < 0) return 0;
  279.       next_hdr = divx_find_header(divx, value - 4);
  280.     } else {
  281.       next_hdr = value;
  282.     }
  283.   }
  284.   // find the next start code, so we have 1 frame in buffer
  285.   // Don't have to worry about going past end of buffer, or buffer length
  286.   // not being enough - we've fixed that problem when initially reading
  287.   // in the file.
  288.   value = divx_find_header(divx, next_hdr + 4);
  289.   if (value < 0) {
  290.     divx_reset_buffer(divx);
  291.     value = divx_find_header(divx, 4);
  292.   }
  293.   *ts = (divx->m_frame_on * M_LLU) / divx->m_framerate;
  294.   *buffer = &divx->m_buffer[divx->m_buffer_on];
  295.   divx->m_frame_on++;
  296.   return divx->m_buffer_size - divx->m_buffer_on;
  297. }
  298. /*
  299.  * divx_file_used_for_frame
  300.  * Tell how many bytes we used
  301.  */
  302. void divx_file_used_for_frame (codec_data_t *your,
  303.        uint32_t bytes)
  304. {
  305.   iso_decode_t *divx = (iso_decode_t *)your;
  306.   divx->m_buffer_on += bytes;
  307. }
  308. /*
  309.  * divx_file_seek_to - find the closest time to ts, start from 
  310.  * there
  311.  */
  312. int divx_file_seek_to (codec_data_t *your, uint64_t ts)
  313. {
  314.   iso_decode_t *divx = (iso_decode_t *)your;
  315.   const frame_file_pos_t *fpos = divx->m_fpos->find_closest_point(ts);
  316.   divx->m_frame_on = fpos->frames;
  317.   divx->m_buffer_on = 0;
  318.   divx->m_buffer_size = 0;
  319.   fseek(divx->m_ifile, fpos->file_position, SEEK_SET);
  320.   divx_reset_buffer(divx);
  321.   return 0;
  322. }
  323. /*
  324.  * divx_file_eof
  325.  * see if we've hit the end of the file
  326.  */
  327. int divx_file_eof (codec_data_t *ifptr)
  328. {
  329.   iso_decode_t *divx = (iso_decode_t *)ifptr;
  330.   return divx->m_buffer_on == divx->m_buffer_size && feof(divx->m_ifile);
  331. }