/////////////////////////////////////////////////////////////////////////////// // // The contents of this file are subject to the Mozilla Public License // Version 1.1 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at // http://www.mozilla.org/MPL/ // // Software distributed under the License is distributed on an "AS IS" // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the // License for the specific language governing rights and limitations // under the License. // // The Original Code is MP4v2. // // The Initial Developer of the Original Code is Kona Blend. // Portions created by Kona Blend are Copyright (C) 2008. // All Rights Reserved. // // Contributors: // Kona Blend, kona8lend@@gmail.com // /////////////////////////////////////////////////////////////////////////////// #include "libutil/impl.h" namespace mp4v2 { namespace util { /////////////////////////////////////////////////////////////////////////////// TrackModifier::TrackModifier( MP4FileHandle file_, uint16_t trackIndex_ ) : _track ( refTrackAtom( *static_cast(file_), trackIndex_ )) , _props ( *this ) // must come after _track is initialized , _enabled ( false ) , _inMovie ( false ) , _inPreview ( false ) , _layer ( 0 ) , _alternateGroup ( 0 ) , _volume ( 1.0f ) , _width ( 0.0f ) , _height ( 0.0f ) , _language ( bmff::ILC_UND ) , _handlerType ( "" ) , _handlerName ( "" ) , _userDataName ( "" ) , file ( *static_cast(file_) ) , trackIndex ( trackIndex_ ) , trackId ( MP4FindTrackId( file_, trackIndex_ )) , enabled ( _enabled ) , inMovie ( _inMovie ) , inPreview ( _inPreview ) , layer ( _layer ) , alternateGroup ( _alternateGroup ) , volume ( _volume ) , width ( _width ) , height ( _height ) , language ( _language ) , handlerType ( _handlerType ) , handlerName ( _handlerName ) , userDataName ( _userDataName ) { fetch(); } /////////////////////////////////////////////////////////////////////////////// TrackModifier::~TrackModifier() { } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::dump( ostream& out, const string& xind ) { const uint32_t w = 14; const string eq = " = "; const string ind = " "; out << left << xind << "track[" << trackIndex << "] id=" << trackId << '\n' << xind << ind << setw( w ) << "type" << eq << toStringTrackType( handlerType ) << '\n' << xind << ind << setw( w ) << "enabled" << eq << toString( enabled ) << '\n' << xind << ind << setw( w ) << "inMovie" << eq << toString( inMovie ) << '\n' << xind << ind << setw( w ) << "inPreview" << eq << toString( inPreview ) << '\n' << xind << ind << setw( w ) << "layer" << eq << layer << '\n' << xind << ind << setw( w ) << "alternateGroup" << eq << alternateGroup << '\n' << xind << ind << setw( w ) << "volume" << eq << toString( volume, 8, 8 ) << '\n' << xind << ind << setw( w ) << "width" << eq << toString( width, 16, 16 ) << '\n' << xind << ind << setw( w ) << "height" << eq << toString( height, 16, 16 ) << '\n' << xind << ind << setw( w ) << "language" << eq << bmff::enumLanguageCode.toString( language, true ) << '\n' << xind << ind << setw( w ) << "handlerName" << eq << handlerName; out << '\n' << xind << ind << setw( w ) << "userDataName" << eq << ( _props.userDataName ? userDataName : "" ); out << '\n'; } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::fetch() { _props.update(); const uint32_t flags = _props.flags.GetValue(); _enabled = flags & 0x01; _inMovie = flags & 0x02; _inPreview = flags & 0x04; _layer = _props.layer.GetValue(); _alternateGroup = _props.alternateGroup.GetValue(); _volume = _props.volume.GetValue(); _width = _props.width.GetValue(); _height = _props.height.GetValue(); _language = _props.language.GetValue(); _handlerType = _props.handlerType.GetValue(); _handlerName = _props.handlerName.GetValue(); if( _props.userDataName ) { uint8_t* buffer; uint32_t size; _props.userDataName->GetValue( &buffer, &size ); _userDataName = string( reinterpret_cast(buffer), size ); } else { _userDataName.clear(); } } /////////////////////////////////////////////////////////////////////////////// bool& TrackModifier::fromString( const string& src, bool& dst ) { if( src == "true" ) dst = true; else if ( src == "false" ) dst = false; else { istringstream iss( src ); iss >> dst; if( iss.rdstate() != ios::eofbit ) { ostringstream oss; oss << "invalid value: " << src; throw new Exception( oss.str(), __FILE__, __LINE__, __FUNCTION__ ); } } return dst; } /////////////////////////////////////////////////////////////////////////////// float& TrackModifier::fromString( const string& src, float& dst ) { istringstream iss( src ); iss >> dst; if( iss.rdstate() != ios::eofbit ) { ostringstream oss; oss << "invalid value: " << src; throw new Exception( oss.str(), __FILE__, __LINE__, __FUNCTION__ ); } return dst; } /////////////////////////////////////////////////////////////////////////////// uint16_t& TrackModifier::fromString( const string& src, uint16_t& dst ) { istringstream iss( src ); iss >> dst; if( iss.rdstate() != ios::eofbit ) { ostringstream oss; oss << "invalid value: " << src; throw new Exception( oss.str(), __FILE__, __LINE__, __FUNCTION__ ); } return dst; } /////////////////////////////////////////////////////////////////////////////// bool TrackModifier::hasUserDataName() const { return _props.userDataName != NULL; } /////////////////////////////////////////////////////////////////////////////// MP4Atom& TrackModifier::refTrackAtom( MP4File& file, uint16_t index ) { MP4Atom& root = *file.FindAtom( NULL ); ostringstream oss; oss << "moov.trak[" << index << "]"; MP4Atom* trak = root.FindAtom( oss.str().c_str() ); if( !trak ) { oss.str( "" ); oss << "trackIndex " << index << " not found"; throw new Exception( oss.str(), __FILE__, __LINE__, __FUNCTION__ ); } return *trak; } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::removeUserDataName() { MP4Atom* name = _track.FindAtom( "trak.udta.name" ); if( name ) name->GetParentAtom()->DeleteChildAtom( name ); MP4Atom* udta = _track.FindAtom( "trak.udta" ); if( udta && !udta->GetNumberOfChildAtoms() ) udta->GetParentAtom()->DeleteChildAtom( udta ); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setAlternateGroup( uint16_t value ) { _props.alternateGroup.SetValue( value ); fetch(); } void TrackModifier::setAlternateGroup( const string& value ) { uint16_t tmp; setAlternateGroup( fromString( value, tmp )); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setEnabled( bool value ) { _enabled = value; _props.flags.SetValue( (_enabled ? 0x01 : 0) | (_inMovie ? 0x02 : 0) | (_inPreview ? 0x04 : 0) ); fetch(); } void TrackModifier::setEnabled( const string& value ) { bool tmp; setEnabled( fromString( value, tmp )); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setHandlerName( const string& value ) { _props.handlerName.SetValue( value.c_str() ); fetch(); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setHeight( float value ) { _props.height.SetValue( value ); fetch(); } void TrackModifier::setHeight( const string& value ) { float tmp; setHeight( fromString( value, tmp )); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setInMovie( bool value ) { _inMovie = value; _props.flags.SetValue( (_enabled ? 0x01 : 0) | (_inMovie ? 0x02 : 0) | (_inPreview ? 0x04 : 0) ); fetch(); } void TrackModifier::setInMovie( const string& value ) { bool tmp; setInMovie( fromString( value, tmp )); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setInPreview( bool value ) { _inPreview = value; _props.flags.SetValue( (_enabled ? 0x01 : 0) | (_inMovie ? 0x02 : 0) | (_inPreview ? 0x04 : 0) ); fetch(); } void TrackModifier::setInPreview( const string& value ) { bool tmp; setInPreview( fromString( value, tmp )); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setLanguage( bmff::LanguageCode value ) { _props.language.SetValue( value ); fetch(); } void TrackModifier::setLanguage( const string& value ) { setLanguage( bmff::enumLanguageCode.toType( value )); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setLayer( uint16_t value ) { _props.layer.SetValue( value ); fetch(); } void TrackModifier::setLayer( const string& value ) { uint16_t tmp; setLayer( fromString( value, tmp )); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setUserDataName( const string& value ) { if( !_props.userDataName ) { ostringstream oss; oss << "moov.trak[" << trackIndex << "]"; file.AddDescendantAtoms( oss.str().c_str(), "udta.name" ); _props.update(); } _props.userDataName->SetValue( reinterpret_cast(value.c_str()), (uint32_t)value.size() ); fetch(); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setVolume( float value ) { _props.volume.SetValue( value ); fetch(); } void TrackModifier::setVolume( const string& value ) { float tmp; setVolume( fromString( value, tmp )); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::setWidth( float value ) { _props.width.SetValue( value ); fetch(); } void TrackModifier::setWidth( const string& value ) { float tmp; setWidth( fromString( value, tmp )); } /////////////////////////////////////////////////////////////////////////////// string TrackModifier::toString( bool value ) { ostringstream oss; oss << (value ? "true" : "false"); return oss.str(); } /////////////////////////////////////////////////////////////////////////////// string TrackModifier::toString( float value, uint8_t i, uint8_t f ) { ostringstream oss; oss << fixed << setprecision(f <= 8 ? 4 : 8) << value; return oss.str(); } /////////////////////////////////////////////////////////////////////////////// string TrackModifier::toStringTrackType( const string& code ) { if( !code.compare( "vide" )) // 14496-12 return "video"; if( !code.compare( "soun" )) // 14496-12 return "audio"; if( !code.compare( "hint" )) // 14496-12 return "hint"; if( !code.compare( "text" )) // QTFF return "text"; if( !code.compare( "tmcd" )) // QTFF return "timecode"; if( !code.compare( "subt" )) // QTFF return "subtitle"; return string( "(" ) + code + ")"; } /////////////////////////////////////////////////////////////////////////////// TrackModifier::Properties::Properties( TrackModifier& trackModifier_ ) : _trackModifier ( trackModifier_ ) , flags ( static_cast ( refProperty( "trak.tkhd.flags" ))) , layer ( static_cast ( refProperty( "trak.tkhd.layer" ))) , alternateGroup ( static_cast ( refProperty( "trak.tkhd.alternate_group" ))) , volume ( static_cast ( refProperty( "trak.tkhd.volume" ))) , width ( static_cast ( refProperty( "trak.tkhd.width" ))) , height ( static_cast ( refProperty( "trak.tkhd.height" ))) , language ( static_cast( refProperty( "trak.mdia.mdhd.language" ))) , handlerType ( static_cast ( refProperty( "trak.mdia.hdlr.handlerType" ))) , handlerName ( static_cast ( refProperty( "trak.mdia.hdlr.name" ))) , userDataName ( static_cast ( findProperty( "trak.udta.name.value" ))) { } /////////////////////////////////////////////////////////////////////////////// MP4Property* TrackModifier::Properties::findProperty( const char* name ) { MP4Property* property; if( !_trackModifier._track.FindProperty( name, &property )) return NULL; return property; } /////////////////////////////////////////////////////////////////////////////// MP4Property& TrackModifier::Properties::refProperty( const char* name ) { MP4Property* property; if( !_trackModifier._track.FindProperty( name, &property )) { ostringstream oss; oss << "trackId " << _trackModifier.trackId << " property '" << name << "' not found"; throw new Exception( oss.str(), __FILE__, __LINE__, __FUNCTION__ ); } return *property; } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::Properties::update() { // update optional properties updateProperty( "trak.udta.name.value", reinterpret_cast( &userDataName )); } /////////////////////////////////////////////////////////////////////////////// void TrackModifier::Properties::updateProperty( const char* name, MP4Property** pp ) { *pp = NULL; _trackModifier._track.FindProperty( name, pp ); } /////////////////////////////////////////////////////////////////////////////// }} // namespace mp4v2::util