| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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<MP4File*>(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<MP4File*>(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( std::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 << std::setw(w) << "type" << eq |
| << toStringTrackType(handlerType) << '\n' |
| << xind << ind << std::setw(w) << "enabled" << eq << toString(enabled) |
| << '\n' |
| << xind << ind << std::setw(w) << "inMovie" << eq << toString(inMovie) |
| << '\n' |
| << xind << ind << std::setw(w) << "inPreview" << eq |
| << toString(inPreview) << '\n' |
| << xind << ind << std::setw(w) << "layer" << eq << layer << '\n' |
| << xind << ind << std::setw(w) << "alternateGroup" << eq |
| << alternateGroup << '\n' |
| << xind << ind << std::setw(w) << "volume" << eq |
| << toString(volume, 8, 8) << '\n' |
| << xind << ind << std::setw(w) << "width" << eq |
| << toString(width, 16, 16) << '\n' |
| << xind << ind << std::setw(w) << "height" << eq |
| << toString(height, 16, 16) << '\n' |
| << xind << ind << std::setw(w) << "language" << eq |
| << bmff::enumLanguageCode.toString(language, true) << '\n' |
| << xind << ind << std::setw(w) << "handlerName" << eq << handlerName; |
| |
| out << '\n' |
| << xind << ind << std::setw(w) << "userDataName" << eq |
| << (_props.userDataName ? userDataName : "<absent>"); |
| |
| 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<char*>(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<const uint8_t*>(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 << std::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<MP4Integer24Property&> ( refProperty( "trak.tkhd.flags" ))) |
| , layer ( static_cast<MP4Integer16Property&> ( refProperty( "trak.tkhd.layer" ))) |
| , alternateGroup ( static_cast<MP4Integer16Property&> ( refProperty( "trak.tkhd.alternate_group" ))) |
| , volume ( static_cast<MP4Float32Property&> ( refProperty( "trak.tkhd.volume" ))) |
| , width ( static_cast<MP4Float32Property&> ( refProperty( "trak.tkhd.width" ))) |
| , height ( static_cast<MP4Float32Property&> ( refProperty( "trak.tkhd.height" ))) |
| , language ( static_cast<MP4LanguageCodeProperty&>( refProperty( "trak.mdia.mdhd.language" ))) |
| , handlerType ( static_cast<MP4StringProperty&> ( refProperty( "trak.mdia.hdlr.handlerType" ))) |
| , handlerName ( static_cast<MP4StringProperty&> ( refProperty( "trak.mdia.hdlr.name" ))) |
| , userDataName ( static_cast<MP4BytesProperty*> ( 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<MP4Property**>( &userDataName )); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| void |
| TrackModifier::Properties::updateProperty( const char* name, MP4Property** pp ) |
| { |
| *pp = NULL; |
| _trackModifier._track.FindProperty( name, pp ); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| }} // namespace mp4v2::util |