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

流媒体/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.  * qtime_file.cpp - provides generic class for quicktime file access control.
  23.  * file access is then used by quicktime audio and video bytestreams.
  24.  */
  25. #include "systems.h"
  26. #include "player_session.h"
  27. #include "player_media.h"
  28. #include "player_util.h"
  29. #include "media_utils.h"
  30. #include <mp4.h>
  31. #include "mp4_bytestream.h"
  32. #include "mp4_file.h"
  33. #include <mp4util/mpeg4_audio_config.h>
  34. #include "our_config_file.h"
  35. #include "codec_plugin_private.h"
  36. /*
  37.  * Create the media for the quicktime file, and set up some session stuff.
  38.  */
  39. static void close_mp4_file (void *data)
  40. {
  41.   CMp4File *Mp4File1 = (CMp4File *)data;
  42.   if (Mp4File1 != NULL) {
  43.     delete Mp4File1;
  44.     Mp4File1 = NULL;
  45.   }
  46. }
  47. int create_media_for_mp4_file (CPlayerSession *psptr, 
  48.        const char *name,
  49.        char *errmsg,
  50.        uint32_t errlen,
  51.        int have_audio_driver,
  52.        control_callback_vft_t *cc_vft)
  53. {
  54.   MP4FileHandle fh;
  55.   CMp4File *Mp4File1;
  56.   fh = MP4Read(name, MP4_DETAILS_ERROR);
  57.   if (!MP4_IS_VALID_FILE_HANDLE(fh)) {
  58.     snprintf(errmsg, errlen, "`%s' is not an mp4 file", name);
  59.     return -1;
  60.   }
  61.   Mp4File1 = new CMp4File(fh);
  62.   // quicktime is searchable...
  63.   psptr->set_media_close_callback(close_mp4_file, (void *)Mp4File1);
  64.   psptr->session_set_seekable(1);
  65.   int ret;
  66.   ret = Mp4File1->create_media(psptr, 
  67.  errmsg, 
  68.  errlen, 
  69.  have_audio_driver,
  70.  cc_vft);
  71.   if (ret <= 0) return ret;
  72.   int offset = 0;
  73.   if (Mp4File1->get_illegal_video_codec() != 0) {
  74.     offset = snprintf(errmsg, errlen, "Unknown or unused Video tracks ");
  75.   }
  76.   if (Mp4File1->have_audio() != 0 && have_audio_driver == 0) {
  77.     offset += snprintf(errmsg + offset, errlen - offset, 
  78.        "%sNo Audio driver - can't play audio",
  79.        offset == 0 ? "" : "and ");
  80.   } else if (Mp4File1->get_illegal_audio_codec() != 0) {
  81.     snprintf(errmsg + offset, errlen - offset, 
  82.      "%sUnknown or unused audio tracks", 
  83.      offset == 0 ? "" : "and ");
  84.   }
  85.   return (1);
  86. }
  87. CMp4File::CMp4File (MP4FileHandle filehandle)
  88. {
  89.   m_mp4file = filehandle;
  90.   m_file_mutex = SDL_CreateMutex();
  91.   m_illegal_audio_codec = 0;
  92.   m_illegal_video_codec = 0;
  93.   m_have_audio = 0;
  94. }
  95. CMp4File::~CMp4File (void)
  96. {
  97.   MP4Close(m_mp4file);
  98.   m_mp4file = NULL;
  99.   if (m_file_mutex) {
  100.     SDL_DestroyMutex(m_file_mutex);
  101.     m_file_mutex = NULL;
  102.   }
  103. }
  104. int CMp4File::create_video(CPlayerSession *psptr, 
  105.    video_query_t *vq, 
  106.    int video_offset,
  107.    char *errmsg, 
  108.    uint32_t errlen,
  109.    int &start_desc)
  110. {
  111.   int ix;
  112.   CPlayerMedia *mptr;
  113.   codec_plugin_t *plugin;
  114.   for (ix = 0; ix < video_offset; ix++) {
  115.     if (vq[ix].enabled != 0) {
  116.       mptr = new CPlayerMedia(psptr);
  117.       if (mptr == NULL) {
  118. return (-1);
  119.       }
  120.       video_info_t *vinfo;
  121.       vinfo = (video_info_t *)malloc(sizeof(video_info_t));
  122.       vinfo->height = vq[ix].h;
  123.       vinfo->width = vq[ix].w;
  124.       plugin = check_for_video_codec("MP4 FILE",
  125.      NULL,
  126.      vq[ix].type,
  127.      vq[ix].profile,
  128.      vq[ix].config, 
  129.      vq[ix].config_len);
  130.       int ret = mptr->create_video_plugin(plugin, 
  131.   NULL, // sdp info
  132.   vinfo, // video info
  133.   vq[ix].config,
  134.   vq[ix].config_len);
  135.       if (ret < 0) {
  136. mp4f_message(LOG_ERR, "Failed to create plugin data");
  137. snprintf(errmsg, errlen, "Failed to start plugin");
  138. delete mptr;
  139. return -1;
  140.       }
  141.       CMp4VideoByteStream *vbyte;
  142.       vbyte = new CMp4VideoByteStream(this, vq[ix].track_id);
  143.       if (vbyte == NULL) {
  144. delete mptr;
  145. return (-1);
  146.       }
  147.       ret = mptr->create_from_file(vbyte, TRUE);
  148.       if (ret != 0) {
  149. return (-1);
  150.       }
  151.       char *mp4info = MP4Info(m_mp4file, vq[ix].track_id);
  152.       char *temp = mp4info;
  153.       while (*temp != '') {
  154. if (isspace(*temp)) *temp = ' ';
  155. if (!isprint(*temp)) *temp = '*';
  156. temp++;
  157.       }
  158.       psptr->set_session_desc(start_desc, mp4info);
  159.       free(mp4info);
  160.       start_desc++;
  161.     } else {
  162.       if (vq[ix].config != NULL) free((void *)vq[ix].config);
  163.     }
  164.   }
  165.   return 0;
  166. }
  167. int CMp4File::create_audio(CPlayerSession *psptr, 
  168.    audio_query_t *aq, 
  169.    int audio_offset,
  170.    char *errmsg,
  171.    uint32_t errlen,
  172.    int &start_desc)
  173. {
  174.   int ix;
  175.   CPlayerMedia *mptr;
  176.   codec_plugin_t *plugin;
  177.   for (ix = 0; ix < audio_offset; ix++) {
  178.     if (aq[ix].enabled != 0) {
  179.       CMp4AudioByteStream *abyte;
  180.       mptr = new CPlayerMedia(psptr);
  181.       if (mptr == NULL) {
  182. return (-1);
  183.       }
  184.       abyte = new CMp4AudioByteStream(this, aq[ix].track_id);
  185.       audio_info_t *ainfo;
  186.       ainfo = (audio_info_t *)malloc(sizeof(audio_info_t));
  187.       memset(ainfo, 0, sizeof(*ainfo));
  188.       ainfo->freq = aq[ix].sampling_freq;
  189.       if (aq[ix].type == MP4_PCM16_AUDIO_TYPE) {
  190. ainfo->bitspersample = 16;
  191.       }
  192.       int ret;
  193.       plugin = check_for_audio_codec("MP4 FILE",
  194.      NULL,
  195.      aq[ix].type,
  196.      aq[ix].profile,
  197.      aq[ix].config,
  198.      aq[ix].config_len);
  199.       ret = mptr->create_audio_plugin(plugin,
  200.       NULL, // sdp info
  201.       ainfo, // audio info
  202.       aq[ix].config,
  203.       aq[ix].config_len);
  204.       if (ret < 0) {
  205. mp4f_message(LOG_ERR, "Couldn't create audio from plugin %s", 
  206.      plugin->c_name);
  207. snprintf(errmsg, errlen, "Couldn't start audio plugin %s", 
  208.  plugin->c_name);
  209. delete mptr;
  210. delete abyte;
  211. return -1;
  212.       }
  213.       ret = mptr->create_from_file(abyte, FALSE);
  214.       if (ret != 0) {
  215. return (-1);
  216.       }
  217.       char *mp4info = MP4Info(m_mp4file, aq[ix].track_id);
  218.       char *temp = mp4info;
  219.       while (*temp != '') {
  220. if (isspace(*temp)) *temp = ' ';
  221. if (!isprint(*temp)) *temp = '*';
  222. temp++;
  223.       }
  224.       psptr->set_session_desc(start_desc, mp4info);
  225.       free(mp4info);
  226.       start_desc++;
  227.     } else {
  228.       if (aq[ix].config != NULL) free((void *)aq[ix].config);
  229.     }
  230.   }
  231.   return 0;
  232. }
  233. int CMp4File::create_media (CPlayerSession *psptr,
  234.     char *errmsg, 
  235.     uint32_t errlen,
  236.     int have_audio_driver,
  237.     control_callback_vft_t *cc_vft)
  238. {
  239.   int video_count, video_offset;
  240.   int audio_count, audio_offset;
  241.   MP4TrackId trackId;
  242.   video_query_t *vq;
  243.   audio_query_t *aq;
  244.   int ix;
  245.   codec_plugin_t *plugin;
  246.   int ret_value = 0;
  247.   video_count = 0;
  248.   do {
  249.     trackId = MP4FindTrackId(m_mp4file, video_count, MP4_VIDEO_TRACK_TYPE);
  250.     if (MP4_IS_VALID_TRACK_ID(trackId)) {
  251.       video_count++;
  252.     }
  253.   } while (MP4_IS_VALID_TRACK_ID(trackId));
  254.   audio_count = 0;
  255.   do {
  256.     trackId = MP4FindTrackId(m_mp4file, audio_count, MP4_AUDIO_TRACK_TYPE);
  257.     
  258.     if (MP4_IS_VALID_TRACK_ID(trackId)) {
  259.       audio_count++;
  260.     }
  261.   } while (MP4_IS_VALID_TRACK_ID(trackId));
  262.   if (video_count == 0 && audio_count == 0) {
  263.     snprintf(errmsg, errlen, "No audio or video tracks in file");
  264.     return -1;
  265.   }
  266.   if (video_count > 0) {
  267.     vq = (video_query_t *)malloc(sizeof(video_query_t) * video_count);
  268.   } else {
  269.     vq = NULL;
  270.   }
  271.   if (have_audio_driver && audio_count > 0) {
  272.     aq = (audio_query_t *)malloc(sizeof(audio_query_t) * audio_count);
  273.   } else {
  274.     aq = NULL;
  275.   }
  276.   for (ix = 0, video_offset = 0; ix < video_count; ix++) {
  277.     trackId = MP4FindTrackId(m_mp4file, ix, MP4_VIDEO_TRACK_TYPE);
  278.     uint8_t video_type = MP4GetTrackVideoType(m_mp4file, trackId);
  279.     uint8_t profileID = MP4GetVideoProfileLevel(m_mp4file);
  280.     mp4f_message(LOG_DEBUG, "MP4 - got track %x profile ID %d", 
  281.  trackId, profileID);
  282.     uint8_t *foo;
  283.     u_int32_t bufsize;
  284.     MP4GetTrackESConfiguration(m_mp4file, trackId, &foo, &bufsize);
  285.     
  286.     plugin = check_for_video_codec("MP4 FILE",
  287.    NULL,
  288.    video_type,
  289.    profileID,
  290.    foo, 
  291.    bufsize);
  292.     if (plugin == NULL) {
  293.       snprintf(errmsg, errlen, 
  294.        "Can't find plugin for video type %d, profile %d",
  295.        video_type, profileID);
  296.       m_illegal_video_codec++;
  297.       ret_value = 1;
  298.     } else {
  299.       vq[video_offset].track_id = trackId;
  300.       vq[video_offset].compressor = "MP4 FILE";
  301.       vq[video_offset].type = video_type;
  302.       vq[video_offset].profile = profileID;
  303.       vq[video_offset].fptr = NULL;
  304.       vq[video_offset].h = MP4GetTrackVideoHeight(m_mp4file, trackId);
  305.       vq[video_offset].w = MP4GetTrackVideoWidth(m_mp4file, trackId);
  306.       vq[video_offset].frame_rate = MP4GetTrackVideoFrameRate(m_mp4file, trackId);
  307.       vq[video_offset].config = foo;
  308.       vq[video_offset].config_len = bufsize;
  309.       vq[video_offset].enabled = 0;
  310.       vq[video_offset].reference = NULL;
  311.       video_offset++;
  312.     }
  313.   }
  314.   audio_offset = 0;
  315.   if (have_audio_driver) {
  316.     for (ix = 0; ix < audio_count; ix++) {
  317.       trackId = MP4FindTrackId(m_mp4file, ix, MP4_AUDIO_TRACK_TYPE);
  318.       uint8_t audio_type;
  319.       uint8_t profile;
  320.       uint8_t *userdata = NULL;
  321.       u_int32_t userdata_size;
  322.       audio_type = MP4GetTrackAudioType(m_mp4file, trackId);
  323.       profile = MP4GetAudioProfileLevel(m_mp4file);
  324.       MP4GetTrackESConfiguration(m_mp4file, 
  325.  trackId, 
  326.  &userdata, 
  327.  &userdata_size);
  328.       plugin = check_for_audio_codec("MP4 FILE",
  329.      NULL,
  330.      audio_type,
  331.      profile,
  332.      userdata,
  333.      userdata_size);
  334.       if (plugin != NULL) {
  335. aq[audio_offset].track_id = trackId;
  336. aq[audio_offset].compressor = "MP4 FILE";
  337. aq[audio_offset].type = audio_type;
  338. aq[audio_offset].profile = profile;
  339. aq[audio_offset].fptr = NULL;
  340. aq[audio_offset].config = userdata;
  341. aq[audio_offset].config_len = userdata_size;
  342. aq[audio_offset].sampling_freq = 
  343.   MP4GetTrackTimeScale(m_mp4file, trackId);
  344. aq[audio_offset].chans = -1;
  345. aq[audio_offset].enabled = 0;
  346. aq[audio_offset].reference = NULL;
  347. audio_offset++;
  348.       } else {
  349. m_illegal_audio_codec++;
  350. ret_value = 1;
  351.       }
  352.     }
  353.   } else {
  354.     if (audio_count)
  355.       ret_value = 1;
  356.   }
  357.   if (cc_vft && cc_vft->media_list_query != NULL) {
  358.     (cc_vft->media_list_query)(psptr, video_offset, vq, audio_offset, aq);
  359.   } else {
  360.     if (video_offset > 0) {
  361.       vq[0].enabled = 1;
  362.     }
  363.     if (audio_offset > 0) {
  364.       aq[0].enabled = 1;
  365.     }
  366.   }
  367.   int ret;
  368.   int start_desc = 1;
  369.   ret = create_video(psptr, vq, video_offset, errmsg, errlen,start_desc);
  370.   free(vq);
  371.   if (ret < 0) {
  372.     free(aq);
  373.     return -1;
  374.   }
  375.  
  376.   ret = create_audio(psptr, aq, audio_offset, errmsg, errlen, start_desc);
  377.   free(aq);
  378.   if (ret < 0) ret_value = -1;
  379.   
  380.   return (ret_value);
  381. }
  382. /* end file mp4_file.cpp */