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

流媒体/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.cpp - implementation with ISO reference codec
  23.  */
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include "codec_plugin.h"
  29. #ifdef _WINDOWS
  30. #include <windows.h>
  31. #include <mmsystem.h>
  32. #endif // __PC_COMPILER_
  33. #include <type/typeapi.h>
  34. #include <sys/mode.hpp>
  35. #include <sys/vopses.hpp>
  36. #include <tools/entropy/bitstrm.hpp>
  37. #include <sys/tps_enhcbuf.hpp>
  38. #include <sys/decoder/enhcbufdec.hpp>
  39. #include <sys/decoder/vopsedec.hpp>
  40. #include "mpeg4.h"
  41. #include <gnu/strcasestr.h>
  42. #ifndef __GLOBAL_VAR_
  43. #define __GLOBAL_VAR_
  44. #endif
  45. #include <sys/global.hpp>
  46. #include <mp4v2/mp4.h>
  47. #include <mp4av/mp4av.h>
  48. #define iso_message (iso->m_vft->log_msg)
  49. static const char *mp4iso = "mp4iso";
  50. // Convert a hex character to it's decimal value.
  51. static char tohex (char a)
  52.   if (isdigit(a))
  53.     return (a - '0');
  54.   return (tolower(a) - 'a' + 10);
  55. }
  56. // Parse the format config passed in.  This is the vo vod header
  57. // that we need to get width/height/frame rate
  58. static int parse_vovod (iso_decode_t *iso,
  59. const char *vovod,
  60. int ascii,
  61. uint32_t len)
  62. {
  63.   unsigned char buffer[255];
  64.   unsigned char *bufptr;
  65.   if (ascii == 1) {
  66.     const char *config = strcasestr(vovod, "config=");
  67.     if (config == NULL) {
  68.       return 0;
  69.     }
  70.     config += strlen("config=");
  71.     const char *end;
  72.     end = config;
  73.     while (isxdigit(*end)) end++;
  74.     if (config == end) {
  75.       return 0;
  76.     }
  77.     // config string will run from config to end
  78.     len = end - config;
  79.     // make sure we have even number of digits to convert to binary
  80.     if ((len % 2) == 1) 
  81.       return 0;
  82.     unsigned char *write;
  83.     write = buffer;
  84.     // Convert the config= from ascii to binary
  85.     for (uint32_t ix = 0; ix < len; ix++) {
  86.       *write = 0;
  87.       *write = (tohex(*config)) << 4;
  88.       config++;
  89.       *write += tohex(*config);
  90.       config++;
  91.       write++;
  92.     }
  93.     len /= 2;
  94.     bufptr = (unsigned char *)&buffer[0];
  95.   } else {
  96.     bufptr = (unsigned char *)vovod;
  97.   }
  98.   // Create a byte stream to take from our buffer.
  99.   // Temporary set of our bytestream
  100.   // Get the VOL header.  If we fail, set the bytestream back
  101.   int havevol = 0;
  102.   do {
  103.     try {
  104.       iso->m_pvodec->SetUpBitstreamBuffer(bufptr, len);
  105.       iso->m_pvodec->decodeVOLHead();
  106.       iso->m_pvodec->postVO_VOLHeadInit(iso->m_pvodec->getWidth(),
  107.    iso->m_pvodec->getHeight(),
  108.    &iso->m_bSpatialScalability);
  109.       iso_message(LOG_DEBUG, mp4iso, "Found VOL in header");
  110.       iso->m_vft->video_configure(iso->m_ifptr, 
  111.   iso->m_pvodec->getWidth(),
  112.   iso->m_pvodec->getHeight(),
  113.   VIDEO_FORMAT_YUV);
  114.       havevol = 1;
  115.     } catch (int err) {
  116.       iso_message(LOG_DEBUG, mp4iso, 
  117.   "Caught exception in VOL mem header search");
  118.     }
  119.     uint32_t used;
  120.     used = iso->m_pvodec->get_used_bytes();
  121.     bufptr += used;
  122.     len -= used;
  123.   } while (havevol == 0 && len > 0);
  124.   // We've found the VO VOL header - that's good.
  125.   // Reset the byte stream back to what it was, delete our temp stream
  126.   //player_debug_message("Decoded vovod header correctly");
  127.   return havevol;
  128. }
  129. static codec_data_t *iso_create (format_list_t *media_fmt,
  130.  video_info_t *vinfo,
  131.  const uint8_t *userdata,
  132.  uint32_t ud_size,
  133.  video_vft_t *vft,
  134.  void *ifptr)
  135. {
  136.   iso_decode_t *iso;
  137.   iso = (iso_decode_t *)malloc(sizeof(iso_decode_t));
  138.   if (iso == NULL) return NULL;
  139.   memset(iso, 0, sizeof(*iso));
  140.   iso->m_vft = vft;
  141.   iso->m_ifptr = ifptr;
  142.   iso->m_main_short_video_header = FALSE;
  143.   iso->m_pvodec = new CVideoObjectDecoder();
  144.   iso->m_decodeState = DECODE_STATE_VOL_SEARCH;
  145.   if (media_fmt != NULL && media_fmt->fmt_param != NULL) {
  146.     // See if we can decode a passed in vovod header
  147.     if (parse_vovod(iso, media_fmt->fmt_param, 1, 0) == 1) {
  148.       iso->m_decodeState = DECODE_STATE_WAIT_I;
  149.     }
  150.   } else if (userdata != NULL) {
  151.     if (parse_vovod(iso, (const char *)userdata, 0, ud_size) == 1) {
  152.       iso->m_decodeState = DECODE_STATE_WAIT_I;
  153.     }
  154.   }
  155.   iso->m_vinfo = vinfo;
  156.   iso->m_num_wait_i = 0;
  157.   iso->m_num_wait_i_frames = 0;
  158.   iso->m_total_frames = 0;
  159.   return (codec_data_t *)iso;
  160. }
  161. void iso_clean_up (iso_decode_t *iso)
  162. {
  163.   if (iso->m_ifile != NULL) {
  164.     fclose(iso->m_ifile);
  165.     iso->m_ifile = NULL;
  166.   }
  167.   if (iso->m_buffer != NULL) {
  168.     free(iso->m_buffer);
  169.     iso->m_buffer = NULL;
  170.   }
  171.   if (iso->m_fpos != NULL) {
  172.     delete iso->m_fpos;
  173.     iso->m_fpos = NULL;
  174.   }
  175.   
  176.   if (iso->m_pvodec) {
  177.     delete iso->m_pvodec;
  178.     iso->m_pvodec = NULL;
  179.   }
  180.   free(iso);
  181. }
  182. static void iso_close (codec_data_t *ptr)
  183. {
  184.   iso_decode_t *iso = (iso_decode_t *)ptr;
  185.   iso_message(LOG_INFO, mp4iso, "MPEG4 codec results:");
  186.   iso_message(LOG_INFO, mp4iso,
  187.       "total frames    : %u", iso->m_total_frames);
  188.   iso_message(LOG_INFO, mp4iso,
  189.       "wait for I times: %u", iso->m_num_wait_i);
  190.   iso_message(LOG_INFO, mp4iso,
  191.       "wait I frames   : %u", iso->m_num_wait_i_frames);
  192.   iso_clean_up(iso);
  193. }
  194. static void iso_do_pause (codec_data_t *ptr)
  195. {
  196.   iso_decode_t *iso = (iso_decode_t *)ptr;
  197.   if (iso->m_decodeState != DECODE_STATE_VOL_SEARCH)
  198.     iso->m_decodeState = DECODE_STATE_WAIT_I;
  199. }
  200. static int iso_frame_is_sync (codec_data_t *ptr,
  201.       uint8_t *buffer, 
  202.       uint32_t buflen,
  203.       void *userdata)
  204. {
  205.   u_char vop_type;
  206.   while (buflen > 3 && 
  207.  !(buffer[0] == 0 && buffer[1] == 0 && 
  208.    buffer[2] == 1 && buffer[3] == MP4AV_MPEG4_VOP_START)) {
  209.     buffer++;
  210.     buflen--;
  211.   }
  212.   vop_type = MP4AV_Mpeg4GetVopType(buffer, buflen);
  213. #if 0
  214.   {
  215.   iso_decode_t *iso = (iso_decode_t *)ptr;
  216.   iso_message(LOG_DEBUG, "iso", "return from get vop is %c %d", vop_type, vop_type);
  217.   }
  218. #endif
  219.   if (vop_type == 'I') return 1;
  220.   return 0;
  221. }
  222. static int iso_decode (codec_data_t *ptr, 
  223.        uint64_t ts, 
  224.        int from_rtp, 
  225.        int *sync_frame,
  226.        uint8_t *buffer,
  227.        uint32_t buflen,
  228.        void *userdata)
  229. {
  230.   Int iEof = 1;
  231.   iso_decode_t *iso = (iso_decode_t *)ptr;
  232.   if (buflen <= 4) return -1;
  233.   iso->m_total_frames++;
  234.   buffer[buflen] = 0;
  235.   buffer[buflen + 1] = 0;
  236.   buffer[buflen + 2] = 1;
  237.   iso->m_pvodec->SetUpBitstreamBuffer((unsigned char *)buffer, buflen + 3);
  238.   switch (iso->m_decodeState) {
  239.   case DECODE_STATE_VOL_SEARCH: {
  240.     uint32_t used = 0;
  241.     while (used < buflen && iso->m_decodeState == DECODE_STATE_VOL_SEARCH) {
  242.       try {
  243. iso->m_pvodec->SetUpBitstreamBuffer((unsigned char *)buffer + used, buflen - used);
  244. iso->m_pvodec->decodeVOLHead();
  245. iso->m_pvodec->postVO_VOLHeadInit(iso->m_pvodec->getWidth(),
  246.   iso->m_pvodec->getHeight(),
  247.   &iso->m_bSpatialScalability);
  248. iso_message(LOG_INFO, mp4iso, "Found VOL");
  249. iso->m_vft->video_configure(iso->m_ifptr, 
  250.     iso->m_pvodec->getWidth(),
  251.     iso->m_pvodec->getHeight(),
  252.     VIDEO_FORMAT_YUV);
  253. iso->m_decodeState = DECODE_STATE_WAIT_I;
  254. used += iso->m_pvodec->get_used_bytes();
  255.       } catch (int err) {
  256. iso_message(LOG_DEBUG, mp4iso, "Caught exception in VOL search %d", err);
  257. if (err == 1) used = buflen;
  258. else used += iso->m_pvodec->get_used_bytes();
  259.       }
  260.     }
  261.     if (iso->m_decodeState != DECODE_STATE_WAIT_I) {
  262.       if (iso->m_vinfo != NULL) {
  263. iso->m_pvodec->FakeOutVOVOLHead(iso->m_vinfo->height,
  264. iso->m_vinfo->width,
  265. 30,
  266. &iso->m_bSpatialScalability);
  267. iso->m_vft->video_configure(iso->m_ifptr, 
  268.     iso->m_vinfo->width,
  269.     iso->m_vinfo->height,
  270.     VIDEO_FORMAT_YUV);
  271. iso->m_decodeState = DECODE_STATE_NORMAL;
  272.       } 
  273.       return used;
  274.     }
  275.     // else fall through
  276.   }
  277.   case DECODE_STATE_WAIT_I:
  278.     try {
  279.       iEof = iso->m_pvodec->decode(NULL, TRUE);
  280.       if (iEof == -1) {
  281. iso->m_num_wait_i_frames++;
  282. return(iso->m_pvodec->get_used_bytes());
  283.       }
  284.       iso_message(LOG_DEBUG, mp4iso, "Back to normal decode");
  285.       iso->m_decodeState = DECODE_STATE_NORMAL;
  286.       iso->m_bCachedRefFrame = FALSE;
  287.       iso->m_bCachedRefFrameCoded = FALSE;
  288.       iso->m_cached_valid = FALSE;
  289.       iso->m_cached_time = 0;
  290.     } catch (int err) {
  291.       if (err != 1)
  292. iso_message(LOG_DEBUG, mp4iso, 
  293.     "ts "LLU",Caught exception in wait_i %d", ts, err);
  294.       return (iso->m_pvodec->get_used_bytes());
  295.       //return (-1);
  296.     }
  297.     break;
  298.   case DECODE_STATE_NORMAL:
  299.     try {
  300.       iEof = iso->m_pvodec->decode(NULL, FALSE, FALSE);
  301.     } catch (int err) {
  302.       // This is because sometimes, the encoder doesn't read all the bytes
  303.       // it should out of the rtp packet.  The rtp bytestream does a read
  304.       // and determines that we're trying to read across bytestreams.
  305.       // If we get this, we don't want to change anything - just fall up
  306.       // to the decoder thread so it gives us a new timestamp.
  307.       if (err == 1) {
  308. // throw from running past end of frame
  309. return -1;
  310.       }
  311.       iso_message(LOG_DEBUG, mp4iso, 
  312.   "Mpeg4 ncaught %d -> waiting for I", err);
  313.       iso->m_decodeState = DECODE_STATE_WAIT_I;
  314.       return (iso->m_pvodec->get_used_bytes());
  315.     } catch (...) {
  316.       iso_message(LOG_DEBUG, mp4iso, 
  317.   "Mpeg4 ncaught -> waiting for I");
  318.       iso->m_decodeState = DECODE_STATE_WAIT_I;
  319.       //return (-1);
  320.       return (iso->m_pvodec->get_used_bytes());
  321.     }
  322.     break;
  323.   }
  324.   /*
  325.    * We've got a good frame.  See if we need to display it
  326.    */
  327.   const CVOPU8YUVBA *pvopcQuant = NULL;
  328.   if (iso->m_pvodec->fSptUsage() == 1) {
  329.     //player_debug_message("Sprite");
  330.   }
  331.   uint64_t displaytime = 0;
  332.   int cached_ts = 0;
  333.   if (iEof == EOF) {
  334.     if (iso->m_bCachedRefFrame) {
  335.       iso->m_bCachedRefFrame = FALSE;
  336.       if (iso->m_bCachedRefFrameCoded) {
  337. pvopcQuant = iso->m_pvodec->pvopcRefQLater();
  338. displaytime = ts;
  339.       }
  340.     }
  341.   } else {
  342.     if (iso->m_pvodec->vopmd().vopPredType == BVOP) {
  343.       if (iEof != FALSE) {
  344. pvopcQuant = iso->m_pvodec->pvopcReconCurr();
  345. displaytime = ts;
  346.       } 
  347.     } else {
  348.       if (iso->m_bCachedRefFrame) {
  349. iso->m_bCachedRefFrame = FALSE;
  350. if (iso->m_bCachedRefFrameCoded) {
  351.   pvopcQuant = iso->m_pvodec->pvopcRefQPrev();
  352.   if (from_rtp) {
  353.     int old_was_valid = iso->m_cached_valid;
  354.     displaytime = iso->m_cached_time;
  355.     cached_ts = 1;
  356.     // old time stamp wasn't valid - instead of calculating it
  357.     // ourselves, just punt on it.
  358.     if (old_was_valid == 0) {
  359.       return (iEof == EOF ? -1 : 0);
  360.     }
  361.   } else {
  362.     displaytime = ts;
  363.   }
  364. }
  365.       }
  366.       iso->m_cached_time = ts;
  367.       iso->m_cached_valid = TRUE;
  368.       iso->m_bCachedRefFrame = TRUE;
  369.       iso->m_bCachedRefFrameCoded = (iEof != FALSE);
  370.     }
  371.   }
  372.   if (pvopcQuant != NULL) {
  373. #if 0
  374.     player_debug_message("frame rtp_ts "LLU" disp "LLU" cached %d", 
  375.  ts, displaytime, cached_ts);
  376. #endif
  377.     /*
  378.      * Get the information to the video sync structure
  379.      */
  380.     const uint8_t *y, *u, *v;
  381.     int pixelw_y, pixelw_uv;
  382.     pixelw_y =  pvopcQuant->getPlane(Y_PLANE)->where().width;
  383.     pixelw_uv = pvopcQuant->getPlane(U_PLANE)->where().width;
  384.     y = (const uint8_t *)pvopcQuant->getPlane(Y_PLANE)->pixels(0,0);
  385.     u = (const uint8_t *)pvopcQuant->getPlane(U_PLANE)->pixels(0,0);
  386.     v = (const uint8_t *)pvopcQuant->getPlane(V_PLANE)->pixels(0,0);
  387.     iso->m_last_time = displaytime;
  388. #if 0
  389.     player_debug_message("Adding video at "LLU" %d", displaytime,
  390.  iso->m_pvodec->vopmd().vopPredType);
  391. #endif
  392.     iso->m_vft->video_have_frame(iso->m_ifptr, 
  393. y, 
  394. u, 
  395. v, 
  396. pixelw_y, 
  397. pixelw_uv, 
  398. displaytime);
  399.   } else {
  400.     iso_message(LOG_DEBUG, mp4iso, "decode but no frame %llu", ts);
  401.   }
  402.   return (iso->m_pvodec->get_used_bytes());
  403. }
  404. static int iso_skip_frame (codec_data_t *iso)
  405. {
  406. #if 0
  407.   return (iso_decode(iso, ts, 0, NULL, buffer, buflen));
  408. #else
  409.   return 0;
  410. #endif
  411. }
  412. static const char *iso_compressors[] = {
  413.   "mp4 ", 
  414.   "mp4v", 
  415.   "divx", 
  416.   "dvx1", 
  417.   "div4", 
  418.   "mpeg4", 
  419.   NULL,
  420. };
  421. static int iso_codec_check (lib_message_func_t message,
  422.     const char *compressor,
  423.     int type,
  424.     int profile,
  425.     format_list_t *fptr,
  426.     const uint8_t *userdata,
  427.     uint32_t userdata_size)
  428. {
  429.   if (compressor != NULL && 
  430.       (strcasecmp(compressor, "MP4 FILE") == 0)) {
  431.     if (type == MP4_MPEG4_VIDEO_TYPE) {
  432.       return 1;
  433.     }
  434.     return -1;
  435.   }
  436.   if (fptr != NULL) {
  437.     // find format. If matches, call parse_fmtp_for_mpeg4, look at
  438.     // profile level.
  439.     if (fptr->rtpmap != NULL && fptr->rtpmap->encode_name != NULL) {
  440.       if (strcasecmp(fptr->rtpmap->encode_name, "MP4V-ES") == 0) {
  441. return 1;
  442.       }
  443.     }
  444.     return -1;
  445.   }
  446.   if (compressor != NULL) {
  447.     const char **lptr = iso_compressors;
  448.     while (*lptr != NULL) {
  449.       if (strcasecmp(*lptr, compressor) == 0) {
  450. return 1;
  451.       }
  452.       lptr++;
  453.     }
  454.   }
  455.   return -1;
  456. }
  457. VIDEO_CODEC_WITH_RAW_FILE_PLUGIN("MPEG4 ISO", 
  458.  iso_create,
  459.  iso_do_pause,
  460.  iso_decode,
  461.  NULL,
  462.  iso_close,
  463.  iso_codec_check,
  464.  iso_frame_is_sync,
  465.  mpeg4_iso_file_check,
  466.  divx_file_next_frame,
  467.  divx_file_used_for_frame,
  468.  divx_file_seek_to,
  469.  iso_skip_frame,
  470.  divx_file_eof);