blob: 7581c63bcea9a0510df8ca785f1cebee118716e5 [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
//
// 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 "impl.h"
namespace mp4v2 { namespace impl { namespace qtff {
///////////////////////////////////////////////////////////////////////////////
namespace {
const string BOX_CODE = "colr";
bool findColorParameterBox( MP4FileHandle file, MP4Atom& coding, MP4Atom*& colr );
}
///////////////////////////////////////////////////////////////////////////////
bool
ColorParameterBox::add( MP4FileHandle file, uint16_t trackIndex, const Item& item )
{
MP4Atom* coding;
if( !MP4_IS_VALID_FILE_HANDLE( file ))
throw new Exception( "invalid file handle", __FILE__, __LINE__, __FUNCTION__ );
if( findCoding( file, trackIndex, coding ))
throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ );
MP4Atom* colr;
if( !findColorParameterBox( file, *coding, colr ))
throw new Exception( "colr-box already exists", __FILE__, __LINE__, __FUNCTION__ );
colr = MP4Atom::CreateAtom( *((MP4File *)file), coding, BOX_CODE.c_str() );
coding->AddChildAtom( colr );
colr->Generate();
MP4StringProperty* type;
MP4Integer16Property* primariesIndex;
MP4Integer16Property* transferFunctionIndex;
MP4Integer16Property* matrixIndex;
if( colr->FindProperty( "colr.colorParameterType", (MP4Property**)&type ))
type->SetValue( "nclc" );
if( colr->FindProperty( "colr.primariesIndex", (MP4Property**)&primariesIndex ))
primariesIndex->SetValue( item.primariesIndex );
if( colr->FindProperty( "colr.transferFunctionIndex", (MP4Property**)&transferFunctionIndex ))
transferFunctionIndex->SetValue( item.transferFunctionIndex );
if( colr->FindProperty( "colr.matrixIndex", (MP4Property**)&matrixIndex ))
matrixIndex->SetValue( item.matrixIndex );
return false;
}
///////////////////////////////////////////////////////////////////////////////
bool
ColorParameterBox::add( MP4FileHandle file, MP4TrackId trackId, const Item& item )
{
MP4File& mp4 = *((MP4File*)file);
return add( file, mp4.FindTrackIndex( trackId ), item );
}
///////////////////////////////////////////////////////////////////////////////
bool
ColorParameterBox::get( MP4FileHandle file, uint16_t trackIndex, Item& item )
{
item.reset();
MP4Atom* coding;
if( findCoding( file, trackIndex, coding ))
throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ );
MP4Atom* colr;
if( findColorParameterBox( file, *coding, colr ))
throw new Exception( "colr-box not found", __FILE__, __LINE__, __FUNCTION__ );
MP4Integer16Property* primariesIndex;
MP4Integer16Property* transferFunctionIndex;
MP4Integer16Property* matrixIndex;
if( colr->FindProperty( "colr.primariesIndex", (MP4Property**)&primariesIndex ))
item.primariesIndex = primariesIndex->GetValue();
if( colr->FindProperty( "colr.transferFunctionIndex", (MP4Property**)&transferFunctionIndex ))
item.transferFunctionIndex = transferFunctionIndex->GetValue();
if( colr->FindProperty( "colr.matrixIndex", (MP4Property**)&matrixIndex ))
item.matrixIndex = matrixIndex->GetValue();
return false;
}
///////////////////////////////////////////////////////////////////////////////
bool
ColorParameterBox::get( MP4FileHandle file, MP4TrackId trackId, Item& item )
{
MP4File& mp4 = *((MP4File*)file);
return get( file, mp4.FindTrackIndex( trackId ), item );
}
///////////////////////////////////////////////////////////////////////////////
bool
ColorParameterBox::list( MP4FileHandle file, ItemList& itemList )
{
itemList.clear();
MP4File& mp4 = *((MP4File*)file);
const uint16_t trackc = mp4.GetNumberOfTracks();
for( uint16_t i = 0; i < trackc; i++) {
MP4TrackId id = mp4.FindTrackId( i );
if( id == MP4_INVALID_TRACK_ID )
continue;
const char* type = mp4.GetTrackType( id );
if( !type )
continue;
itemList.resize( itemList.size() + 1 );
IndexedItem& xitem = itemList[itemList.size()-1];
xitem.trackIndex = i;
xitem.trackId = id;
bool success = false;
try {
success = !get( file, i, xitem.item );
}
catch( Exception* x ) {
delete x;
}
if( !success ) {
itemList.resize( itemList.size() - 1 );
continue;
}
}
return false;
}
///////////////////////////////////////////////////////////////////////////////
bool
ColorParameterBox::remove( MP4FileHandle file, uint16_t trackIndex )
{
MP4Atom* coding;
if( findCoding( file, trackIndex, coding ))
throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ );
MP4Atom* colr;
if( findColorParameterBox( file, *coding, colr ))
throw new Exception( "colr-box not found", __FILE__, __LINE__, __FUNCTION__ );
coding->DeleteChildAtom( colr );
delete colr;
return false;
}
///////////////////////////////////////////////////////////////////////////////
bool
ColorParameterBox::remove( MP4FileHandle file, MP4TrackId trackId )
{
MP4File& mp4 = *((MP4File*)file);
return remove( file, mp4.FindTrackIndex( trackId ));
}
///////////////////////////////////////////////////////////////////////////////
bool
ColorParameterBox::set( MP4FileHandle file, uint16_t trackIndex, const Item& item )
{
MP4Atom* coding;
if( findCoding( file, trackIndex, coding ))
throw new Exception( "supported coding not found", __FILE__, __LINE__, __FUNCTION__ );
MP4Atom* colr;
if( findColorParameterBox( file, *coding, colr ))
throw new Exception( "colr-box not found", __FILE__, __LINE__, __FUNCTION__ );
MP4Integer16Property* primariesIndex;
MP4Integer16Property* transferFunctionIndex;
MP4Integer16Property* matrixIndex;
if( colr->FindProperty( "colr.primariesIndex", (MP4Property**)&primariesIndex ))
primariesIndex->SetValue( item.primariesIndex );
if( colr->FindProperty( "colr.transferFunctionIndex", (MP4Property**)&transferFunctionIndex ))
transferFunctionIndex->SetValue( item.transferFunctionIndex );
if( colr->FindProperty( "colr.matrixIndex", (MP4Property**)&matrixIndex ))
matrixIndex->SetValue( item.matrixIndex );
return false;
}
///////////////////////////////////////////////////////////////////////////////
bool
ColorParameterBox::set( MP4FileHandle file, MP4TrackId trackId, const Item& item )
{
MP4File& mp4 = *((MP4File*)file);
return set( file, mp4.FindTrackIndex( trackId ), item );
}
///////////////////////////////////////////////////////////////////////////////
ColorParameterBox::IndexedItem::IndexedItem()
: trackIndex ( numeric_limits<uint16_t>::max() )
, trackId ( MP4_INVALID_TRACK_ID )
{
}
///////////////////////////////////////////////////////////////////////////////
ColorParameterBox::Item::Item()
: primariesIndex ( 6 )
, transferFunctionIndex ( 1 )
, matrixIndex ( 6 )
{
}
///////////////////////////////////////////////////////////////////////////////
void
ColorParameterBox::Item::convertFromCSV( const string& text )
{
istringstream iss( text );
char delim;
iss >> primariesIndex;
iss >> delim;
iss >> transferFunctionIndex;
iss >> delim;
iss >> matrixIndex;
// input was good if we end up with only eofbit set
if( iss.rdstate() != ios::eofbit ) {
reset();
ostringstream xss;
xss << "invalid ColorParameterBox format"
<< " (expecting: INDEX1,INDEX2,INDEX3)"
<< " got: " << text;
throw new Exception( xss.str(), __FILE__, __LINE__, __FUNCTION__ );
}
}
///////////////////////////////////////////////////////////////////////////////
string
ColorParameterBox::Item::convertToCSV() const
{
string buffer;
return convertToCSV( buffer );
}
///////////////////////////////////////////////////////////////////////////////
string&
ColorParameterBox::Item::convertToCSV( string& buffer ) const
{
ostringstream oss;
oss << primariesIndex << ',' << transferFunctionIndex << ',' << matrixIndex;
buffer = oss.str();
return buffer;
}
///////////////////////////////////////////////////////////////////////////////
void
ColorParameterBox::Item::reset()
{
primariesIndex = 6;
transferFunctionIndex = 1;
matrixIndex = 6;
}
///////////////////////////////////////////////////////////////////////////////
namespace {
///////////////////////////////////////////////////////////////////////////////
bool
findColorParameterBox( MP4FileHandle file, MP4Atom& coding, MP4Atom*& colr )
{
colr = NULL;
MP4Atom* found = NULL;
const uint32_t atomc = coding.GetNumberOfChildAtoms();
for( uint32_t i = 0; i < atomc; i++ ) {
MP4Atom* atom = coding.GetChildAtom( i );
if( BOX_CODE != atom->GetType() )
continue;
found = atom;
}
if( !found )
return true;
MP4StringProperty* type;
if( !found->FindProperty( "colr.colorParameterType", (MP4Property**)&type ))
return true;
const string type_nclc = "nclc";
if( type_nclc != type->GetValue() )
return true;
colr = found;
return false;
}
///////////////////////////////////////////////////////////////////////////////
} // anonymous
///////////////////////////////////////////////////////////////////////////////
}}} // namespace mp4v2::impl::qtff