Exemple #1
0
/** Action for setting chapters every n second in <b>job.file</b>
 *
 *  
 *  @param job the job to process
 *  @return mp4v2::util::SUCCESS if successful, mp4v2::util::FAILURE otherwise
 */
bool
ChapterUtility::actionEvery( JobContext& job )
{
    ostringstream oss;
    oss << "Setting " << getChapterTypeName( _ChapterType ) << " chapters every "
        << _ChaptersEvery << " seconds in file " << '"' << job.file << '"' << endl;

    verbose1f( "%s", oss.str().c_str() );
    if( dryrunAbort() )
    {
        return SUCCESS;
    }

    job.fileHandle = MP4Modify( job.file.c_str() );
    if( job.fileHandle == MP4_INVALID_FILE_HANDLE )
    {
        return herrf( "unable to open for write: %s\n", job.file.c_str() );
    }

    bool isVideoTrack = false;
    MP4TrackId refTrackId = getReferencingTrack( job.fileHandle, isVideoTrack );
    if( !MP4_IS_VALID_TRACK_ID(refTrackId) )
    {
        return herrf( "unable to find a video or audio track in file %s\n", job.file.c_str() );
    }

    Timecode refTrackDuration( MP4GetTrackDuration( job.fileHandle, refTrackId ), MP4GetTrackTimeScale( job.fileHandle, refTrackId ) );
    refTrackDuration.setScale( CHAPTERTIMESCALE );

    Timecode chapterDuration( _ChaptersEvery * 1000, CHAPTERTIMESCALE );
    chapterDuration.setFormat( Timecode::DECIMAL );
    vector<MP4Chapter_t> chapters;

    do
    {
        MP4Chapter_t chap;
        chap.duration = refTrackDuration.duration > chapterDuration.duration ? chapterDuration.duration : refTrackDuration.duration;
        sprintf(chap.title, "Chapter %lu", (unsigned long)chapters.size()+1);

        chapters.push_back( chap );
        refTrackDuration -= chapterDuration;
    }
    while( refTrackDuration.duration > 0 );

    if( 0 < chapters.size() )
    {
        MP4SetChapters(job.fileHandle, &chapters[0], (uint32_t)chapters.size(), _ChapterType);
    }

    fixQtScale( job.fileHandle );
    job.optimizeApplicable = true;

    return SUCCESS;
}
Exemple #2
0
/** Fix a QuickTime/iPod issue with long audio files.
 *
 *  This function checks if the <b>file</b> is a long audio file (more than
 *  about 6 1/2 hours) and modifies the timescale if necessary to allow
 *  playback of the file in QuickTime player and on some iPod models.
 *
 *  @param file the opened MP4 file
 */
void
ChapterUtility::fixQtScale(MP4FileHandle file)
{
    // get around a QuickTime/iPod issue with storing the number of samples in a signed 32Bit value
    if( INT_MAX < MP4GetDuration(file))
    {
        bool isVideoTrack = false;
        if( MP4_IS_VALID_TRACK_ID(getReferencingTrack( file, isVideoTrack )) & isVideoTrack )
        {
            // if it is a video, everything is different
            return;
        }

        // timescale too high, lower it
        MP4ChangeMovieTimeScale(file, 1000);
    }
}
Exemple #3
0
/** Action for importing chapters into the <b>job.file</b>
 *
 *  
 *  @param job the job to process
 *  @return mp4v2::util::SUCCESS if successful, mp4v2::util::FAILURE otherwise
 */
bool
ChapterUtility::actionImport( JobContext& job )
{
    vector<MP4Chapter_t> chapters;
    Timecode::Format format;

    // create the chapter file name
    string inName = job.file;
    if( _ChapterFile.empty() )
    {
        FileSystem::pathnameStripExtension( inName );
        inName.append( ".chapters.txt" );
    }
    else
    {
        inName = _ChapterFile;
    }

    if( parseChapterFile( inName, chapters, format ) )
    {
        return FAILURE;
    }

    ostringstream oss;
    oss << "Importing " << chapters.size() << " " << getChapterTypeName( _ChapterType );
    oss << " chapters from file " << inName << " into file " << '"' << job.file << '"' << endl;

    verbose1f( "%s", oss.str().c_str() );
    if( dryrunAbort() )
    {
        return SUCCESS;
    }

    if( 0 == chapters.size() )
    {
        return herrf( "No chapters found in file %s\n", inName.c_str() );
    }

    job.fileHandle = MP4Modify( job.file.c_str() );
    if( job.fileHandle == MP4_INVALID_FILE_HANDLE )
    {
        return herrf( "unable to open for write: %s\n", job.file.c_str() );
    }

    bool isVideoTrack = false;
    MP4TrackId refTrackId = getReferencingTrack( job.fileHandle, isVideoTrack );
    if( !MP4_IS_VALID_TRACK_ID(refTrackId) )
    {
        return herrf( "unable to find a video or audio track in file %s\n", job.file.c_str() );
    }
    if( Timecode::FRAME == format && !isVideoTrack )
    {
        // we need a video track for this
        return herrf( "unable to find a video track in file %s but chapter file contains frame timestamps\n", job.file.c_str() );
    }

    // get duration and recalculate scale
    Timecode refTrackDuration( MP4GetTrackDuration( job.fileHandle, refTrackId ),
                               MP4GetTrackTimeScale( job.fileHandle, refTrackId ) );
    refTrackDuration.setScale( CHAPTERTIMESCALE );

    // check for chapters starting after duration of reftrack
    for( vector<MP4Chapter_t>::iterator it = chapters.begin(); it != chapters.end(); )
    {
        Timecode curr( (*it).duration, CHAPTERTIMESCALE );
        if( refTrackDuration <= curr )
        {
            hwarnf( "Chapter '%s' start: %s, playlength of file: %s, chapter cannot be set\n",
                    (*it).title, curr.svalue.c_str(), refTrackDuration.svalue.c_str() );
            it = chapters.erase( it );
        }
        else
        {
            ++it;
        }
    }
    if( 0 == chapters.size() )
    {
        return SUCCESS;
    }

    // convert start time into duration
	uint32_t framerate = static_cast<uint32_t>( CHAPTERTIMESCALE );
    if( Timecode::FRAME == format )
    {
        // get the framerate
        MP4SampleId sampleCount = MP4GetTrackNumberOfSamples( job.fileHandle, refTrackId );
        Timecode tmpcd( refTrackDuration.svalue, CHAPTERTIMESCALE );
		framerate = static_cast<uint32_t>( std::ceil( ((double)sampleCount / (double)tmpcd.duration) * CHAPTERTIMESCALE ) );
    }

    for( vector<MP4Chapter_t>::iterator it = chapters.begin(); it != chapters.end(); ++it )
    {
        MP4Duration currDur = (*it).duration;
        MP4Duration nextDur =  chapters.end() == it+1 ? refTrackDuration.duration : (*(it+1)).duration;

        if( Timecode::FRAME == format )
        {
            // convert from frame nr to milliseconds
            currDur = convertFrameToMillis( (*it).duration, framerate );

            if( chapters.end() != it+1 )
            {
                nextDur = convertFrameToMillis( (*(it+1)).duration, framerate );
            }
        }

        (*it).duration = nextDur - currDur;
    }

    // now set the chapters
    MP4SetChapters( job.fileHandle, &chapters[0], (uint32_t)chapters.size(), _ChapterType );

    fixQtScale( job.fileHandle );
    job.optimizeApplicable = true;

    return SUCCESS;
}
bool mpeg_video_recorder::InitRecording(int width, int height){
	coid::charstr mp4FileName(m_sVideoFolderPath);
	mp4FileName << "capture_";
	mp4FileName << coid::msec_timer::get_time();
	mp4FileName << ".mp4";
	MP4FileHandle fileHandle = MP4Create(mp4FileName.c_str(), MP4FileMode::FILEMODE_CREATE);
	if (!MP4_IS_VALID_FILE_HANDLE(fileHandle)){
		coid::charstr msg;
		msg << ERRORMESSAGE(" ");
		msg << "Can't create Mp4 file! Path: " << mp4FileName;
		log(msg);
		return false;
	}

	m_IsRecording = true;
	m_hMp4FileHandle = fileHandle;
	m_iVideoTrackID = MP4_INVALID_TRACK_ID;

	coid::bifstream cfgFile(m_sVideoFolderPath+"x264.cfg");
	coid::fmtstreamcxx fmt;
	coid::metastream meta(fmt);

	if (cfgFile.is_open()){
		try{
			fmt.bind(cfgFile);
			meta.stream_in(m_oX264Cfg);
		}
		catch (coid::exception& e){

		}
	}
	else{
		log(WARNINGMESSAGE("x264 configuration file does not exists!"));
		fmt.bind(coid::nullstream);
		meta.xstream_in(m_oX264Cfg);
	}

	meta.stream_acknowledge();
	
	x264_param_t param;
	x264_param_default_preset(&param, m_oX264Cfg.m_sPreset.c_str(), "zerolatency");
	param.i_threads = m_oX264Cfg.m_iThreadCount;
	param.i_width = width;
	param.i_height = height;
	param.i_fps_num = 30;
	param.i_fps_den = 1;
	// Intra refres:
	param.i_keyint_max = 30;
	param.b_intra_refresh = 1;
	//Rate control:
	param.rc.i_rc_method = X264_RC_CRF;
	param.rc.f_rf_constant = 25;
	param.rc.f_rf_constant_max = 35;
	//For streaming:
	param.b_repeat_headers = 1;
	param.b_annexb = 1;
	x264_param_apply_profile(&param, "baseline");

	m_pEncoder = x264_encoder_open(&param);

	MP4TrackId videoTrackID = MP4AddH264VideoTrack(m_hMp4FileHandle, 90000, MP4_INVALID_DURATION, width, height, 0, 1, 0, 3);
	if (!MP4_IS_VALID_TRACK_ID(videoTrackID)){
		MP4Close(m_hMp4FileHandle);
		return false;
	}

	m_iVideoTrackID = videoTrackID;

	m_iWidth = width;
	m_iHeight = height;

	m_pLastNals = NULL;
	m_uiLastTimestampNs = 0;
	m_uiFrameIndex = 0;

	return true;
}
Exemple #5
0
int main (int argc, char *argv[])
{
  int len = 0;
  char *allargs = NULL, *step;
  argc--;
  argv++;

  while (argc > 0 && strcasestr(*argv, ".mp4") != NULL) {
    MP4FileHandle mp4File;

    mp4File = MP4Read(*argv, MP4_DETAILS_ERROR);
    if (MP4_IS_VALID_FILE_HANDLE(mp4File)) {
      MP4TrackId tid;
      uint32_t ix = 0;
      do {
	uint32_t verb = MP4GetVerbosity(mp4File);
	MP4SetVerbosity(mp4File, verb & ~(MP4_DETAILS_ERROR));
	tid = MP4FindTrackId(mp4File, ix, MP4_VIDEO_TRACK_TYPE);
	MP4SetVerbosity(mp4File, verb);
	if (MP4_IS_VALID_TRACK_ID(tid)) {
	  uint8_t type = MP4GetTrackEsdsObjectTypeId(mp4File, tid);
	  if (type == MP4_MPEG4_VIDEO_TYPE) {
	    uint8_t *foo;
	    uint32_t bufsize;
	    MP4GetTrackESConfiguration(mp4File, tid, &foo, &bufsize);
	    if (foo != NULL && bufsize != 0) {
	      printf("%s\n", *argv);
	      decode(foo, bufsize);
	      free(foo);
	    } else {
	      fprintf(stderr, "%s - track %d - can't find esds\n", *argv, tid);
	    }
	  } else {
	    fprintf(stderr, "%s - track %d is not MPEG4 - type %u\n", 
		    *argv, tid, type);
	  }

	}
	ix++;
      } while (MP4_IS_VALID_TRACK_ID(tid));
    } else {
      fprintf(stderr, "%s is not a valid mp4 file\n", *argv);
    }
    argc--;
    argv++;
  }
  if (argc > 0) {
	len = 1;
    while (argc > 0) {
      len += strlen(*argv);
	  if (allargs == NULL) {
		  allargs = (char *)malloc(len);
		  allargs[0] = '\0';
	  } else 
         allargs = (char *)realloc(allargs, len);
      strcat(allargs, *argv);
      argv++;
      argc--;
    }
    if ((len - 1) & 0x1) {
      fprintf(stderr, "odd length VOL\n");
      exit(1);
    }
    len /= 2;
    uint8_t *vol = (uint8_t *)malloc(len), *write;
    write = vol;
    step = allargs;
    int ix;
    for (ix = 0; ix < len; ix++) {
      *write = 0;
      *write = tohex(*step) << 4;
      step++;
      *write |= tohex(*step);
      step++;
      write++;
    }
  
    printf("decoding vol \"%s\"\n", allargs);
    decode(vol, len);
  }

  return(0);
}
Exemple #6
0
void MP4File::MakeIsmaCompliant(bool addIsmaComplianceSdp)
{
    ProtectWriteOperation("MP4MakeIsmaCompliant");

    if (m_useIsma) {
        // already done
        return;
    }
    m_useIsma = true;

    // find first audio and/or video tracks

    MP4TrackId audioTrackId = MP4_INVALID_TRACK_ID;
    try {
        audioTrackId = FindTrackId(0, MP4_AUDIO_TRACK_TYPE);
    }
    catch (MP4Error* e) {
        delete e;
    }

    MP4TrackId videoTrackId = MP4_INVALID_TRACK_ID;
    try {
        videoTrackId = FindTrackId(0, MP4_VIDEO_TRACK_TYPE);
    }
    catch (MP4Error* e) {
        delete e;
    }

    u_int64_t fileMsDuration =
        ConvertFromMovieDuration(GetDuration(), MP4_MSECS_TIME_SCALE);

    // delete any existing OD track
    if (m_odTrackId != MP4_INVALID_TRACK_ID) {
        DeleteTrack(m_odTrackId);
    }

    AddODTrack();
    SetODProfileLevel(0xFF);

    if (audioTrackId != MP4_INVALID_TRACK_ID) {
        AddTrackToOd(audioTrackId);
    }

    if (videoTrackId != MP4_INVALID_TRACK_ID) {
        AddTrackToOd(videoTrackId);
    }

    // delete any existing scene track
    MP4TrackId sceneTrackId = MP4_INVALID_TRACK_ID;
    try {
        sceneTrackId = FindTrackId(0, MP4_SCENE_TRACK_TYPE);
    }
    catch (MP4Error *e) {
        delete e;
    }
    if (sceneTrackId != MP4_INVALID_TRACK_ID) {
        DeleteTrack(sceneTrackId);
    }

    // add scene track
    sceneTrackId = AddSceneTrack();
    SetSceneProfileLevel(0xFF);
    SetGraphicsProfileLevel(0xFF);
    SetTrackIntegerProperty(sceneTrackId,
                            "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId",
                            MP4SystemsV2ObjectType);

    SetTrackESConfiguration(sceneTrackId,
                            BifsV2Config, sizeof(BifsV2Config));

    u_int8_t* pBytes = NULL;
    u_int64_t numBytes = 0;

    // write OD Update Command
    CreateIsmaODUpdateCommandFromFileForFile(
        m_odTrackId,
        audioTrackId,
        videoTrackId,
        &pBytes,
        &numBytes);

    WriteSample(m_odTrackId, pBytes, numBytes, fileMsDuration);

    MP4Free(pBytes);
    pBytes = NULL;

    // write BIFS Scene Replace Command
    CreateIsmaSceneCommand(
        MP4_IS_VALID_TRACK_ID(audioTrackId),
        MP4_IS_VALID_TRACK_ID(videoTrackId),
        &pBytes,
        &numBytes);

    WriteSample(sceneTrackId, pBytes, numBytes, fileMsDuration);

    MP4Free(pBytes);
    pBytes = NULL;

    // add session level sdp
    CreateIsmaIodFromFile(
        m_odTrackId,
        sceneTrackId,
        audioTrackId,
        videoTrackId,
        &pBytes,
        &numBytes);

    char* iodBase64 = MP4ToBase64(pBytes, numBytes);

    char* sdpBuf = (char*)MP4Calloc(strlen(iodBase64) + 256);

    if (addIsmaComplianceSdp) {
        strcpy(sdpBuf, "a=isma-compliance:1,1.0,1\015\012");
    }

    sprintf(&sdpBuf[strlen(sdpBuf)],
            "a=mpeg4-iod: \042data:application/mpeg4-iod;base64,%s\042\015\012",
            iodBase64);

    SetSessionSdp(sdpBuf);

    VERBOSE_ISMA(GetVerbosity(),
                 printf("IOD SDP = %s\n", sdpBuf));

    MP4Free(iodBase64);
    iodBase64 = NULL;
    MP4Free(pBytes);
    pBytes = NULL;
    MP4Free(sdpBuf);
    sdpBuf = NULL;
}
Exemple #7
0
void MP4File::CreateIsmaIodFromFile(
    MP4TrackId odTrackId,
    MP4TrackId sceneTrackId,
    MP4TrackId audioTrackId,
    MP4TrackId videoTrackId,
    u_int8_t** ppBytes,
    u_int64_t* pNumBytes)
{
    MP4Descriptor* pIod = new MP4IODescriptor();
    pIod->SetTag(MP4IODescrTag);
    pIod->Generate();

    MP4Atom* pIodsAtom = FindAtom("moov.iods");
    ASSERT(pIodsAtom);
    MP4DescriptorProperty* pSrcIod =
        (MP4DescriptorProperty*)pIodsAtom->GetProperty(2);

    CloneIntegerProperty(pIod, pSrcIod, "objectDescriptorId");
    CloneIntegerProperty(pIod, pSrcIod, "ODProfileLevelId");
    CloneIntegerProperty(pIod, pSrcIod, "sceneProfileLevelId");
    CloneIntegerProperty(pIod, pSrcIod, "audioProfileLevelId");
    CloneIntegerProperty(pIod, pSrcIod, "visualProfileLevelId");
    CloneIntegerProperty(pIod, pSrcIod, "graphicsProfileLevelId");

    // mutate esIds from MP4ESIDIncDescrTag to MP4ESDescrTag
    MP4DescriptorProperty* pEsProperty;
    pIod->FindProperty("esIds", (MP4Property**)&pEsProperty);
    pEsProperty->SetTags(MP4ESDescrTag);

    MP4IntegerProperty* pSetProperty;
    MP4IntegerProperty* pSceneESID;
    MP4IntegerProperty* pOdESID;

    // OD
    MP4Descriptor* pOdEsd =
        pEsProperty->AddDescriptor(MP4ESDescrTag);
    pOdEsd->Generate();

    pOdEsd->FindProperty("ESID",
                         (MP4Property**)&pOdESID);

    // we set the OD ESID to a non-zero unique value
    pOdESID->SetValue(m_odTrackId);

    pOdEsd->FindProperty("URLFlag",
                         (MP4Property**)&pSetProperty);
    pSetProperty->SetValue(1);

    u_int8_t* pBytes;
    u_int64_t numBytes;

    CreateIsmaODUpdateCommandFromFileForStream(
        audioTrackId,
        videoTrackId,
        &pBytes,
        &numBytes);

    VERBOSE_ISMA(GetVerbosity(),
                 printf("OD data =\n"); MP4HexDump(pBytes, numBytes));

    char* odCmdBase64 = MP4ToBase64(pBytes, numBytes);

    char* urlBuf = (char*)MP4Malloc(strlen(odCmdBase64) + 64);

    sprintf(urlBuf,
            "data:application/mpeg4-od-au;base64,%s",
            odCmdBase64);

    MP4StringProperty* pUrlProperty;
    pOdEsd->FindProperty("URL",
                         (MP4Property**)&pUrlProperty);
    pUrlProperty->SetValue(urlBuf);

    VERBOSE_ISMA(GetVerbosity(),
                 printf("OD data URL = \042%s\042\n", urlBuf));

    MP4Free(odCmdBase64);
    odCmdBase64 = NULL;
    MP4Free(pBytes);
    pBytes = NULL;
    MP4Free(urlBuf);
    urlBuf = NULL;

    MP4DescriptorProperty* pSrcDcd = NULL;

    // HACK temporarily point to scene decoder config
    FindProperty(MakeTrackName(odTrackId,
                               "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"),
                 (MP4Property**)&pSrcDcd);
    ASSERT(pSrcDcd);
    MP4Property* pOrgOdEsdProperty =
        pOdEsd->GetProperty(8);
    pOdEsd->SetProperty(8, pSrcDcd);

    // bufferSizeDB needs to be set appropriately
    MP4BitfieldProperty* pBufferSizeProperty = NULL;
    pOdEsd->FindProperty("decConfigDescr.bufferSizeDB",
                         (MP4Property**)&pBufferSizeProperty);
    ASSERT(pBufferSizeProperty);
    pBufferSizeProperty->SetValue(numBytes);

    // SL config needs to change from 2 (file) to 1 (null)
    pOdEsd->FindProperty("slConfigDescr.predefined",
                         (MP4Property**)&pSetProperty);
    pSetProperty->SetValue(1);


    // Scene
    MP4Descriptor* pSceneEsd =
        pEsProperty->AddDescriptor(MP4ESDescrTag);
    pSceneEsd->Generate();

    pSceneEsd->FindProperty("ESID",
                            (MP4Property**)&pSceneESID);
    // we set the Scene ESID to a non-zero unique value
    pSceneESID->SetValue(sceneTrackId);

    pSceneEsd->FindProperty("URLFlag",
                            (MP4Property**)&pSetProperty);
    pSetProperty->SetValue(1);

    CreateIsmaSceneCommand(
        MP4_IS_VALID_TRACK_ID(audioTrackId),
        MP4_IS_VALID_TRACK_ID(videoTrackId),
        &pBytes,
        &numBytes);

    VERBOSE_ISMA(GetVerbosity(),
                 printf("Scene data =\n"); MP4HexDump(pBytes, numBytes));

    char *sceneCmdBase64 = MP4ToBase64(pBytes, numBytes);

    urlBuf = (char*)MP4Malloc(strlen(sceneCmdBase64) + 64);
    sprintf(urlBuf,
            "data:application/mpeg4-bifs-au;base64,%s",
            sceneCmdBase64);

    pSceneEsd->FindProperty("URL",
                            (MP4Property**)&pUrlProperty);
    pUrlProperty->SetValue(urlBuf);

    VERBOSE_ISMA(GetVerbosity(),
                 printf("Scene data URL = \042%s\042\n", urlBuf));

    MP4Free(sceneCmdBase64);
    sceneCmdBase64 = NULL;
    MP4Free(urlBuf);
    urlBuf = NULL;
    MP4Free(pBytes);
    pBytes = NULL;

    // HACK temporarily point to scene decoder config
    FindProperty(MakeTrackName(sceneTrackId,
                               "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr"),
                 (MP4Property**)&pSrcDcd);
    ASSERT(pSrcDcd);
    MP4Property* pOrgSceneEsdProperty =
        pSceneEsd->GetProperty(8);
    pSceneEsd->SetProperty(8, pSrcDcd);

    // bufferSizeDB needs to be set
    pBufferSizeProperty = NULL;
    pSceneEsd->FindProperty("decConfigDescr.bufferSizeDB",
                            (MP4Property**)&pBufferSizeProperty);
    ASSERT(pBufferSizeProperty);
    pBufferSizeProperty->SetValue(numBytes);

    // SL config needs to change from 2 (file) to 1 (null)
    pSceneEsd->FindProperty("slConfigDescr.predefined",
                            (MP4Property**)&pSetProperty);
    pSetProperty->SetValue(1);


    // finally get the whole thing written to a memory
    pIod->WriteToMemory(this, ppBytes, pNumBytes);


    // now carefully replace esd properties before destroying
    pOdEsd->SetProperty(8, pOrgOdEsdProperty);
    pSceneEsd->SetProperty(8, pOrgSceneEsdProperty);
    pSceneESID->SetValue(0); // restore 0 value
    pOdESID->SetValue(0);

    delete pIod;

    VERBOSE_ISMA(GetVerbosity(),
                 printf("IOD data =\n"); MP4HexDump(*ppBytes, *pNumBytes));
}