xvid_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. 2002.  All Rights Reserved.
  17.  * 
  18.  * Contributor(s): 
  19.  *              Bill May        wmay@cisco.com
  20.  */
  21. /*
  22.  * xvid_file.cpp
  23.  * Read a raw file for xvid.
  24.  */
  25. #include "ourxvid.h"
  26. #include "xvid.h"
  27. #include "divx4.h"
  28. /*
  29.  * xvid_find_header
  30.  * Search buffer to find the next start code
  31.  */
  32. static int xvid_find_header (xvid_codec_t *xvid,
  33.      uint32_t start_offset)
  34. {
  35.   for (uint32_t ix = start_offset; ix + 4 < xvid->m_buffer_size; ix++) {
  36.     if ((xvid->m_buffer[ix] == 0) &&
  37. (xvid->m_buffer[ix + 1] == 0) &&
  38. (xvid->m_buffer[ix + 2] == 1)) {
  39.       return ix;
  40.     }
  41.   }
  42.   return -1;
  43. }
  44. /*
  45.  * xvid_reset_buffer
  46.  * Move end of buffer to beginning, fill in rest of buffer
  47.  */
  48. static int xvid_reset_buffer (xvid_codec_t *xvid)
  49. {      
  50.   uint32_t diff, read;
  51.   if (xvid->m_buffer_size > xvid->m_buffer_on) {
  52.     diff = xvid->m_buffer_size - xvid->m_buffer_on;
  53.     memmove(xvid->m_buffer,
  54.     &xvid->m_buffer[xvid->m_buffer_on],
  55.     diff);
  56.   } else diff = 0;
  57.   xvid->m_buffer_size = diff;
  58.   read = fread(xvid->m_buffer + diff, 
  59.        1, 
  60.        xvid->m_buffer_size_max - diff,
  61.        xvid->m_ifile);
  62.   xvid->m_buffer_on = 0;
  63.   if (read <= 0) {
  64.     if (xvid->m_buffer_size < 4) xvid->m_buffer_size = 0;
  65.     return -1;
  66.   }
  67.   xvid->m_buffer_size += read;
  68.   if (xvid->m_buffer_size < 4) xvid->m_buffer_size = 0;
  69.   return diff;
  70. }
  71. /*
  72.  * xvid_buffer_load
  73.  * Make sure we have at least 1 full VOP frame in the buffer
  74.  */
  75. static int xvid_buffer_load (xvid_codec_t *xvid, uint8_t *ftype) 
  76. {
  77.   int next_hdr, left, value;
  78.   if (xvid->m_buffer_on + 3 >= xvid->m_buffer_size) {
  79.     if (xvid_reset_buffer(xvid) < 0) return -1;
  80.   }
  81.   next_hdr = xvid_find_header(xvid, xvid->m_buffer_on);
  82.   if (next_hdr < 0) return -1;
  83.   // We've got the first header pointed to by m_buffer_on
  84.   xvid->m_buffer_on = next_hdr;
  85.   // Is it a VOP header ?  If not, find the first VOP header
  86.   if (xvid->m_buffer[next_hdr + 3] != 0xb6) {
  87.     value = 0;
  88.     do {
  89.       // Increment when we've got a header pointed to by next_hdr
  90.       if (value >= 0) next_hdr += 4;
  91.       value = xvid_find_header(xvid, next_hdr);
  92.       if (value < 0) {
  93. if (xvid->m_buffer_on == 0 &&
  94.   xvid->m_buffer_size == xvid->m_buffer_size_max) {
  95.   // weirdness has happened.  We've got a full buffer of
  96.   // headers, no frames
  97.   return -1;
  98. }
  99. left = xvid_reset_buffer(xvid);
  100. if (left < 0) {
  101.   // No more new data - we've reached the end... 
  102.   return xvid->m_buffer_size;
  103. }
  104. // okay - this case is gross - we'll start checking from the
  105. // beginning
  106. next_hdr = left - 4;
  107.       } else {
  108. next_hdr = value;
  109.       }
  110.     } while (value < 0 || xvid->m_buffer[next_hdr + 3] != 0xb6);
  111.   }
  112.   // next_hdr contains the location of the first VOP.
  113.   // Record the file type (top 2 bits) after 00 00 01 b6
  114.   *ftype = xvid->m_buffer[next_hdr + 4];
  115.   // Find the next header.
  116.   value = xvid_find_header(xvid, next_hdr + 4);
  117.   if (value >= 0) {
  118.     // Cool - it's in the header...
  119.     return value;
  120.   }
  121.   //
  122.   // Not in the header - reset the buffer, then continue search
  123.   //
  124.   value = xvid->m_buffer_size - xvid->m_buffer_on;
  125.   left = xvid_reset_buffer(xvid);
  126.   if (left < 0) return xvid->m_buffer_size;
  127.   value = xvid_find_header(xvid, value);
  128.   if (value >= 0) {
  129.     return value;
  130.   }
  131.   // We don't have enough read in... Go forward
  132.   while (xvid->m_buffer_size_max < 65535) {
  133.     int old, readsize;
  134.     xvid->m_buffer = (uint8_t *)realloc(xvid->m_buffer,
  135.       xvid->m_buffer_size_max + 1024);
  136.     readsize = fread(&xvid->m_buffer[xvid->m_buffer_size_max],
  137.      1, 
  138.      1024, 
  139.      xvid->m_ifile);
  140.     if (readsize <= 0) {
  141.       return (xvid->m_buffer_size - xvid->m_buffer_on);
  142.     }
  143.     old = xvid->m_buffer_size;
  144.     xvid->m_buffer_size += readsize;
  145.     xvid->m_buffer_size_max += 1024;
  146.     value = xvid_find_header(xvid, old - 4);
  147.     if (value >= 0) return value;
  148.   }
  149.   return -1;
  150. }
  151. /*
  152.  * xvid_file_check
  153.  * Check the file.  If it's a .xvid file, look for the VOL, and record
  154.  * where the I frames are.
  155.  */
  156. codec_data_t *xvid_file_check (lib_message_func_t message,
  157.        const char *name, 
  158.        double *max,
  159.        char *desc[4])
  160. {
  161.   int len;
  162.   xvid_codec_t *xvid;
  163.   uint32_t framecount = 0;
  164.   uint64_t calc;
  165.   XVID_INIT_PARAM xvid_param;
  166.   /*
  167.    * Compare with .xvid extension
  168.    */
  169.   len = strlen(name);
  170.   if (!((strcasecmp(name + len - 5, ".divx") == 0) ||
  171. (strcasecmp(name + len - 5, ".xvid") == 0))) {
  172.     return NULL;
  173.   }
  174.   /*
  175.    * Malloc the xvid structure, init some variables
  176.    */
  177.   xvid = MALLOC_STRUCTURE(xvid_codec_t);
  178.   memset(xvid, 0, sizeof(*xvid));
  179.   
  180.   xvid_param.cpu_flags = 0;
  181.   xvid_init(NULL, 0, &xvid_param, NULL);
  182.   XVID_DEC_PARAM dec_param;
  183.   xvid_decore(NULL, XVID_DEC_ALLOC, &dec_param, NULL);
  184.   xvid->m_xvid_handle = dec_param.handle;
  185.   xvid->m_decodeState = XVID_STATE_VO_SEARCH;
  186.   xvid->m_ifile = fopen(name, FOPEN_READ_BINARY);
  187.   if (xvid->m_ifile == NULL) {
  188.     free(xvid);
  189.     return NULL;
  190.   }
  191.   xvid->m_buffer = (uint8_t *)malloc(16 * 1024);
  192.   xvid->m_buffer_size_max = 16 * 1024;
  193.   xvid->m_fpos = new CFilePosRecorder();
  194.   xvid->m_fpos->record_point(0, 0, 0);
  195.   /*
  196.    * Start searching the file, find the VOL, mark the I frames
  197.    */
  198.   int havevol = 0;
  199.   int nextframe;
  200.   uint8_t ftype;
  201.   nextframe = xvid_buffer_load(xvid, &ftype);
  202.   do {
  203.     if (havevol == 0) {
  204.       XVID_DEC_FRAME frame;
  205.       XVID_DEC_PARAM param;
  206.       frame.bitstream = (void *)&xvid->m_buffer[xvid->m_buffer_on];
  207.       frame.length = xvid->m_buffer_size - xvid->m_buffer_on;
  208.       int ret = xvid_decore(xvid->m_xvid_handle,
  209.     XVID_DEC_FIND_VOL,
  210.     &frame, 
  211.     &param);
  212.       if (ret == XVID_ERR_OK) {
  213. havevol = 1;
  214. message(LOG_DEBUG, "xvid", "Found vol in xvid file");
  215. // we really need the frames per second from the timestamps...
  216. xvid->m_buffer_on = nextframe;
  217.       } else
  218. xvid->m_buffer_on = xvid->m_buffer_size - 3;
  219.     } else {
  220.       // If we have an I_VOP, mark it.
  221.       if ((ftype & 0xc0) == 0) {
  222. calc = framecount * 1000;
  223. calc /= 30;
  224. //message(LOG_DEBUG, "xvid", "I frame at %u "LLU, framecount, calc);
  225. xvid->m_fpos->record_point(ftell(xvid->m_ifile) - 
  226.    xvid->m_buffer_size - 
  227.    xvid->m_buffer_on, 
  228.    calc, 
  229.    framecount);
  230.       }
  231.       xvid->m_buffer_on = nextframe;
  232.     }
  233.     framecount++;
  234.     nextframe = xvid_buffer_load(xvid, &ftype);
  235.   } while (nextframe != -1);
  236.   if (havevol == 0) {
  237.     xvid_clean_up(xvid);
  238.     return NULL;
  239.   }
  240.   *max = (double)framecount / 30.0; //(double)mp4_hdr.fps;
  241.   rewind(xvid->m_ifile);
  242.   return ((codec_data_t *)xvid);
  243.     
  244. }
  245. /*
  246.  * xvid_file_next_frame
  247.  * Read in the next frame, return timestamp
  248.  */
  249. int xvid_file_next_frame (codec_data_t *your_data,
  250.   uint8_t **buffer, 
  251.   uint64_t *ts)
  252. {
  253.   xvid_codec_t *xvid;
  254.   int next_hdr, value;
  255.   xvid = (xvid_codec_t *)your_data;
  256.   // start at the next header
  257.   next_hdr = xvid_find_header(xvid, xvid->m_buffer_on);
  258.   if (next_hdr < 0) {
  259.     next_hdr = xvid_reset_buffer(xvid);
  260.     if (next_hdr < 0) return 0;
  261.     next_hdr = xvid_find_header(xvid, next_hdr);
  262.     if (next_hdr < 0) return 0;
  263.   }
  264.   xvid->m_buffer_on = next_hdr;
  265.   value = 0;
  266.   // find first vop
  267.   while (xvid->m_buffer[next_hdr + 3] != 0xb6) {
  268.     value = xvid_find_header(xvid, next_hdr + 4);
  269.     if (value < 0) {
  270.       value = xvid_reset_buffer(xvid);
  271.       if (value < 0) return 0;
  272.       next_hdr = xvid_find_header(xvid, value - 4);
  273.     } else {
  274.       next_hdr = value;
  275.     }
  276.   }
  277.   // find the next start code, so we have 1 frame in buffer
  278.   // Don't have to worry about going past end of buffer, or buffer length
  279.   // not being enough - we've fixed that problem when initially reading
  280.   // in the file.
  281.   value = xvid_find_header(xvid, next_hdr + 4);
  282.   if (value < 0) {
  283.     xvid_reset_buffer(xvid);
  284.     value = xvid_find_header(xvid, 4);
  285.   }
  286.   *ts = (xvid->m_frame_on * M_LLU) / 30; //mp4_hdr.fps;
  287.   *buffer = &xvid->m_buffer[xvid->m_buffer_on];
  288.   xvid->m_frame_on++;
  289.   return xvid->m_buffer_size - xvid->m_buffer_on;
  290. }
  291. /*
  292.  * xvid_file_used_for_frame
  293.  * Tell how many bytes we used
  294.  */
  295. void xvid_file_used_for_frame (codec_data_t *your,
  296.        uint32_t bytes)
  297. {
  298.   xvid_codec_t *xvid = (xvid_codec_t *)your;
  299.   xvid->m_buffer_on += bytes;
  300. }
  301. /*
  302.  * xvid_file_seek_to - find the closest time to ts, start from 
  303.  * there
  304.  */
  305. int xvid_file_seek_to (codec_data_t *your, uint64_t ts)
  306. {
  307.   xvid_codec_t *xvid = (xvid_codec_t *)your;
  308.   const frame_file_pos_t *fpos = xvid->m_fpos->find_closest_point(ts);
  309.   xvid->m_frame_on = fpos->frames;
  310.   xvid->m_buffer_on = 0;
  311.   xvid->m_buffer_size = 0;
  312.   fseek(xvid->m_ifile, fpos->file_position, SEEK_SET);
  313.   xvid_reset_buffer(xvid);
  314.   return 0;
  315. }
  316. /*
  317.  * xvid_file_eof
  318.  * see if we've hit the end of the file
  319.  */
  320. int xvid_file_eof (codec_data_t *ifptr)
  321. {
  322.   xvid_codec_t *xvid = (xvid_codec_t *)ifptr;
  323.   return xvid->m_buffer_on == xvid->m_buffer_size && feof(xvid->m_ifile);
  324. }