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

流媒体/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.  * ourxvid.cpp - plugin interface with xvid decoder.
  23.  */
  24. #include "ourxvid.h"
  25. #include "codec_plugin.h"
  26. #include <mp4util/mpeg4_sdp.h>
  27. #include <gnu/strcasestr.h>
  28. #include <mp4v2/mp4.h>
  29. #include <xvid.h>
  30. #include <divx4.h>
  31. #include <mp4av/mp4av.h>
  32. #define xvid_message (xvid->m_vft->log_msg)
  33. // Convert a hex character to it's decimal value.
  34. static char tohex (char a)
  35.   if (isdigit(a))
  36.     return (a - '0');
  37.   return (tolower(a) - 'a' + 10);
  38. }
  39. // Parse the format config passed in.  This is the vo vod header
  40. // that we need to get width/height/frame rate
  41. static int parse_vovod (xvid_codec_t *xvid,
  42. const char *vovod,
  43. int ascii,
  44. uint32_t len)
  45. {
  46.   unsigned char buffer[255];
  47.   const char *bufptr;
  48.   int ret;
  49.   if (ascii == 1) {
  50.     const char *config = strcasestr(vovod, "config=");
  51.     if (config == NULL) {
  52.       return 0;
  53.     }
  54.     config += strlen("config=");
  55.     const char *end;
  56.     end = config;
  57.     while (isxdigit(*end)) end++;
  58.     if (config == end) {
  59.       return 0;
  60.     }
  61.     // config string will run from config to end
  62.     len = end - config;
  63.     // make sure we have even number of digits to convert to binary
  64.     if ((len % 2) == 1) 
  65.       return 0;
  66.     unsigned char *write;
  67.     write = buffer;
  68.     // Convert the config= from ascii to binary
  69.     for (uint32_t ix = 0; ix < len; ix++) {
  70.       *write = 0;
  71.       *write = (tohex(*config)) << 4;
  72.       config++;
  73.       *write += tohex(*config);
  74.       config++;
  75.       write++;
  76.     }
  77.     len /= 2;
  78.     bufptr = (const char *)buffer;
  79.   } else {
  80.     bufptr = vovod;
  81.   }
  82.   
  83.   // Get the VO/VOL header.  If we fail, set the bytestream back
  84.   ret = 0;
  85.   XVID_DEC_FRAME frame;
  86.   XVID_DEC_PARAM param;
  87.   frame.bitstream = (void *)bufptr;
  88.   frame.length = len;
  89.   ret = xvid_decore(xvid->m_xvid_handle, XVID_DEC_FIND_VOL,
  90.     &frame, &param);
  91.   if (ret == XVID_ERR_OK) {
  92.     xvid_message(LOG_DEBUG, "xvid", "found vol %d %d", 
  93.  param.width, param.height);
  94.     xvid->m_vft->video_configure(xvid->m_ifptr, 
  95.  param.width,
  96.  param.height,
  97.  VIDEO_FORMAT_YUV);
  98.   }
  99.   return ret;
  100. }
  101. static codec_data_t *xvid_create (format_list_t *media_fmt,
  102.   video_info_t *vinfo,
  103.   const uint8_t *userdata,
  104.   uint32_t ud_size,
  105.   video_vft_t *vft,
  106.   void *ifptr)
  107. {
  108.   xvid_codec_t *xvid;
  109.   xvid = MALLOC_STRUCTURE(xvid_codec_t);
  110.   memset(xvid, 0, sizeof(*xvid));
  111.   xvid->m_vft = vft;
  112.   xvid->m_ifptr = ifptr;
  113.   XVID_INIT_PARAM xvid_param;
  114.   xvid_param.cpu_flags = 0;
  115.   xvid_init(NULL, 0, &xvid_param, NULL);
  116.   XVID_DEC_PARAM dec_param;
  117.   xvid_decore(NULL, XVID_DEC_ALLOC, &dec_param, NULL);
  118.   xvid->m_xvid_handle = dec_param.handle;
  119.   xvid->m_decodeState = XVID_STATE_VO_SEARCH;
  120.   if (media_fmt != NULL && media_fmt->fmt_param != NULL) {
  121.     // See if we can decode a passed in vovod header
  122.     if (parse_vovod(xvid, media_fmt->fmt_param, 1, 0) == XVID_ERR_OK) {
  123.       xvid->m_decodeState = XVID_STATE_WAIT_I;
  124.     }
  125.   } else if (userdata != NULL) {
  126.     if (parse_vovod(xvid, (const char *)userdata, 0, ud_size) == XVID_ERR_OK) {
  127.       xvid->m_decodeState = XVID_STATE_WAIT_I;
  128.     }
  129.   } 
  130.   xvid->m_vinfo = vinfo;
  131.   xvid->m_num_wait_i = 0;
  132.   xvid->m_num_wait_i_frames = 0;
  133.   xvid->m_total_frames = 0;
  134.   return ((codec_data_t *)xvid);
  135. }
  136. void xvid_clean_up (xvid_codec_t *xvid)
  137. {
  138.   if (xvid->m_xvid_handle != NULL) {
  139.     xvid_decore(xvid->m_xvid_handle, XVID_DEC_DESTROY, NULL, NULL);
  140.     xvid->m_xvid_handle = NULL;
  141.   }
  142.   if (xvid->m_ifile != NULL) {
  143.     fclose(xvid->m_ifile);
  144.     xvid->m_ifile = NULL;
  145.   }
  146.   if (xvid->m_buffer != NULL) {
  147.     free(xvid->m_buffer);
  148.     xvid->m_buffer = NULL;
  149.   }
  150.   if (xvid->m_fpos != NULL) {
  151.     delete xvid->m_fpos;
  152.     xvid->m_fpos = NULL;
  153.   }
  154.   free(xvid);
  155. }
  156. static void xvid_close (codec_data_t *ifptr)
  157. {
  158.   xvid_codec_t *xvid;
  159.   xvid = (xvid_codec_t *)ifptr;
  160.   xvid_message(LOG_NOTICE, "xvidif", "Xvid codec results:");
  161.   xvid_message(LOG_NOTICE, "xvidif", "total frames    : %u", xvid->m_total_frames);
  162.   xvid_message(LOG_NOTICE, "xvidif", "wait for I times: %u", xvid->m_num_wait_i);
  163.   xvid_message(LOG_NOTICE, "xvidif", "wait I frames   : %u", xvid->m_num_wait_i_frames);
  164.   xvid_clean_up(xvid);
  165. }
  166. static void xvid_do_pause (codec_data_t *ifptr)
  167. {
  168.   xvid_codec_t *xvid = (xvid_codec_t *)ifptr;
  169.   if (xvid->m_decodeState != XVID_STATE_VO_SEARCH)
  170.     xvid->m_decodeState = XVID_STATE_WAIT_I;
  171. }
  172. static int xvid_frame_is_sync (codec_data_t *ptr,
  173.        uint8_t *buffer, 
  174.        uint32_t buflen,
  175.        void *userdata)
  176. {
  177.   u_char vop_type;
  178.   while (buflen > 3 && 
  179.  !(buffer[0] == 0 && buffer[1] == 0 && 
  180.    buffer[2] == 1 && buffer[3] == MP4AV_MPEG4_VOP_START)) {
  181.     buffer++;
  182.     buflen--;
  183.   }
  184.   vop_type = MP4AV_Mpeg4GetVopType(buffer, buflen);
  185.   if (vop_type == 'I') return 1;
  186.   return 0;
  187. }
  188. static int xvid_decode (codec_data_t *ptr,
  189. uint64_t ts, 
  190. int from_rtp,
  191. int *sync_frame,
  192. uint8_t *buffer, 
  193. uint32_t buflen,
  194. void *ud)
  195. {
  196.   int ret;
  197.   int do_wait_i = 0;
  198.   xvid_codec_t *xvid = (xvid_codec_t *)ptr;
  199.   XVID_DEC_FRAME frame;
  200. #if 0
  201.   xvid->m_vft->log_msg(LOG_DEBUG, "xvid", " %d frame %llu len %u %d", 
  202.        xvid->m_total_frames, ts, buflen,
  203.        xvid->m_decodeState);
  204. #endif
  205.   xvid->m_total_frames++;
  206.   frame.bitstream = buffer;
  207.   frame.length = buflen;
  208.   
  209.   switch (xvid->m_decodeState) {
  210.   case XVID_STATE_VO_SEARCH:
  211.     XVID_DEC_PARAM param;
  212.     ret = xvid_decore(xvid->m_xvid_handle, 
  213.       XVID_DEC_FIND_VOL,
  214.       &frame,
  215.       &param);
  216.     if (ret > 0) {
  217. xvid->m_decodeState = XVID_STATE_WAIT_I;
  218. xvid->m_vft->video_configure(xvid->m_ifptr, 
  219.      param.width,
  220.      param.height,
  221.      VIDEO_FORMAT_YUV);
  222.     } else {
  223.       xvid_decore(xvid->m_xvid_handle, XVID_DEC_DESTROY, NULL, NULL);
  224.       xvid->m_xvid_handle = NULL;
  225.       XVID_DEC_PARAM dec_param;
  226.       dec_param.width = xvid->m_vinfo->width;
  227.       dec_param.height = xvid->m_vinfo->height;
  228.       xvid_decore(NULL, XVID_DEC_CREATE, &dec_param, NULL);
  229.       xvid->m_xvid_handle = dec_param.handle;
  230.       xvid->m_vft->video_configure(xvid->m_ifptr, 
  231.    xvid->m_vinfo->width,
  232.    xvid->m_vinfo->height,
  233.    VIDEO_FORMAT_YUV);
  234.       xvid->m_decodeState = XVID_STATE_NORMAL;
  235.     } 
  236.     break;
  237.   case XVID_STATE_WAIT_I:
  238.     do_wait_i = 1;
  239.     break;
  240.   case XVID_STATE_NORMAL:
  241.     break;
  242.   }
  243.   
  244.   frame.colorspace = XVID_CSP_USER;
  245.   DEC_PICTURE decpict;
  246.   frame.image = &decpict;
  247.   ret = xvid_decore(xvid->m_xvid_handle, XVID_DEC_DECODE, &frame, NULL);
  248.   if (ret == XVID_ERR_OK) {
  249.     xvid->m_vft->video_have_frame(xvid->m_ifptr,
  250.   (const uint8_t *)decpict.y,
  251.   (const uint8_t *)decpict.u,
  252.   (const uint8_t *)decpict.v,
  253.   decpict.stride_y,
  254.   decpict.stride_uv,
  255.   ts);
  256.     ret = frame.length;
  257.   } else {
  258. #if 0
  259.     xvid->m_vft->log_msg(LOG_DEBUG, "xvid", "error returned %d", ret);
  260. #endif
  261.   }
  262.       
  263.   return (ret);
  264. }
  265. static int xvid_skip_frame (codec_data_t *ifptr)
  266. {
  267.   return 0;
  268. }
  269. static const char *xvid_compressors[] = {
  270.   "xvid", 
  271.   "divx",
  272.   "dvx1", 
  273.   "div4", 
  274.   NULL,
  275. };
  276. static int xvid_codec_check (lib_message_func_t message,
  277.      const char *compressor,
  278.      int type,
  279.      int profile,
  280.      format_list_t *fptr,
  281.      const uint8_t *userdata,
  282.      uint32_t userdata_size)
  283. {
  284.   if (compressor != NULL && 
  285.       (strcasecmp(compressor, "MP4 FILE") == 0)) {
  286.     if ((type == MP4_MPEG4_VIDEO_TYPE) &&
  287. (profile >= 1 && profile <= 3)) {
  288.       return 3;
  289.     }
  290.     return -1;
  291.   }
  292.   if (fptr != NULL) {
  293.     // find format. If matches, call parse_fmtp_for_mpeg4, look at
  294.     // profile level.
  295.     if (fptr->rtpmap != NULL && fptr->rtpmap->encode_name != NULL) {
  296.       if (strcasecmp(fptr->rtpmap->encode_name, "MP4V-ES") == 0) {
  297. fmtp_parse_t *fmtp;
  298. fmtp = parse_fmtp_for_mpeg4(fptr->fmt_param, message);
  299. if (fmtp != NULL) {
  300.   int profile = fmtp->profile_level_id;
  301.   free_fmtp_parse(fmtp);
  302.   if (profile >= 1 && profile <= 3) return 3;
  303. }
  304. return -1;
  305.       }
  306.     }
  307.     return -1;
  308.   }
  309.   if (compressor != NULL) {
  310.     const char **lptr = xvid_compressors;
  311.     while (*lptr != NULL) {
  312.       if (strcasecmp(*lptr, compressor) == 0) {
  313. return 3;
  314.       }
  315.       lptr++;
  316.     }
  317.   }
  318.   return -1;
  319. }
  320. VIDEO_CODEC_WITH_RAW_FILE_PLUGIN("xvid", 
  321.  xvid_create,
  322.  xvid_do_pause,
  323.  xvid_decode,
  324.  NULL,
  325.  xvid_close,
  326.  xvid_codec_check,
  327.  xvid_frame_is_sync,
  328.  xvid_file_check,
  329.  xvid_file_next_frame,
  330.  xvid_file_used_for_frame,
  331.  xvid_file_seek_to,
  332.  xvid_skip_frame,
  333.  xvid_file_eof);