/* Add the meta data that lavf exposes to the movie */ static void add_metadata(AVFormatContext *ic, Movie theMovie) { QTMetaDataRef movie_metadata; OSType err; err = QTCopyMovieMetaData(theMovie, &movie_metadata); if (err) return; void (^AddMetaDataItem)(const char *, OSType) = ^(const char *ff_name, OSType qt_name) { AVDictionaryEntry *e = av_dict_get(ic->metadata, ff_name, NULL, 0); if (!e) return; QTMetaDataAddItem(movie_metadata, kQTMetaDataStorageFormatQuickTime, kQTMetaDataKeyFormatCommon, (UInt8*)&qt_name, sizeof(qt_name), (UInt8*)e->value, strlen(e->value), kQTMetaDataTypeUTF8, NULL); }; AddMetaDataItem("title", kQTMetaDataCommonKeyDisplayName); AddMetaDataItem("author", kQTMetaDataCommonKeyAuthor); AddMetaDataItem("artist", kQTMetaDataCommonKeyArtist); AddMetaDataItem("copyright", kQTMetaDataCommonKeyCopyright); AddMetaDataItem("comment", kQTMetaDataCommonKeyComment); AddMetaDataItem("album", kQTMetaDataCommonKeyAlbum); AddMetaDataItem("genre", kQTMetaDataCommonKeyGenre); AddMetaDataItem("composer", kQTMetaDataCommonKeyComposer); AddMetaDataItem("encoder", kQTMetaDataCommonKeySoftware); // TODO iTunes track number, disc number, ... QTMetaDataRelease(movie_metadata); }
void QTImportFileHandle::AddMetadata(Tags *tags) { QTMetaDataRef metaDataRef = NULL; auto cleanup = finally( [&] { // we are done so release our metadata object if ( metaDataRef ) QTMetaDataRelease(metaDataRef); } ); OSErr err; err = QTCopyMovieMetaData(mMovie, &metaDataRef); if (err != noErr) { return; } for (int i = 0; i < WXSIZEOF(names); i++) { QTMetaDataItem item = kQTMetaDataItemUninitialized; // OSType key = names[i].key; err = QTMetaDataGetNextItem(metaDataRef, kQTMetaDataStorageFormatWildcard, kQTMetaDataItemUninitialized, kQTMetaDataKeyFormatCommon, (const UInt8 *) &names[i].key, sizeof(names[i].key), &item); if (err != noErr) { continue; } if (item == kQTMetaDataItemUninitialized) { continue; } QTPropertyValueType outPropType; ::ByteCount outPropValueSize; ::ByteCount outPropValueSizeUsed = 0; UInt32 outPropFlags; UInt32 dataType; // Get data type err = QTMetaDataGetItemProperty(metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_DataType, sizeof(dataType), &dataType, &outPropValueSizeUsed); if (err != noErr) { continue; } // Get the data length err = QTMetaDataGetItemPropertyInfo(metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_Value, &outPropType, &outPropValueSize, &outPropFlags ); if (err != noErr) { continue; } // Alloc memory for it ArrayOf<char> outVals{ outPropValueSize }; // Retrieve the data err = QTMetaDataGetItemProperty(metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_Value, outPropValueSize, outVals.get(), &outPropValueSizeUsed); if (err != noErr) continue; wxString v = wxT(""); switch (dataType) { case kQTMetaDataTypeUTF8: v = wxString(outVals.get(), wxConvUTF8); break; case kQTMetaDataTypeUTF16BE: { wxMBConvUTF16BE conv; v = wxString(outVals.get(), conv); } break; } if (!v.IsEmpty()) { tags->SetTag(names[i].name, v); } } return; }
void DumpMovieMetaData(Movie theMovie) { require(nil != theMovie, NILMOVIE); // get movie metadata reference which is necessary to iterate // all the metadata items QTMetaDataRef metaDataRef; OSStatus status = QTCopyMovieMetaData (theMovie, &metaDataRef ); require_noerr(status, NOMETADATAREF); // get count of total number of metadata items for *all* container formats ItemCount outCount=0; status = MDUtils_GetStorageFormatCountForAllFormats(metaDataRef, &outCount); DrawStorageCountStrToWindow("Total for all", outCount); DrawStringToFrontWindow(CFSTR("\n")); DrawStringToFrontWindow(CFSTR("details:\n")); DrawStringToFrontWindow(CFSTR("\n")); // display metadata item count values for each of the different storage formats ItemCount iTunesShortCount=0, iTunesLongCount=0, UserDataCount=0, QTDataCount=0; status = MDUtils_GetiTunesStorageFormatShortFormCount(metaDataRef, &iTunesShortCount); status = MDUtils_GetiTunesStorageFormatLongFormCount(metaDataRef, &iTunesLongCount); status = MDUtils_GetUserDataStorageFormatCount(metaDataRef, &UserDataCount); status = MDUtils_GetQuickTimeDataStorageFormatCount(metaDataRef, &QTDataCount); DrawStorageCountStrToWindow("iTunes ShortForm", iTunesShortCount); DrawStorageCountStrToWindow("iTunes LongForm", iTunesLongCount); DrawStorageCountStrToWindow("User Data", UserDataCount); DrawStorageCountStrToWindow("QuickTime", QTDataCount); if (outCount) { DrawStringToFrontWindow(CFSTR("--------------------------------------------\n")); DrawStringToFrontWindow(CFSTR("Key for Metadata Item Display:\n")); DrawStringToFrontWindow(CFSTR("\n")); DrawStringToFrontWindow(CFSTR("- storage format\n")); DrawStringToFrontWindow(CFSTR("- key\n")); DrawStringToFrontWindow(CFSTR("- keyformat\n")); DrawStringToFrontWindow(CFSTR("- locale\n")); DrawStringToFrontWindow(CFSTR("- data type\n")); DrawStringToFrontWindow(CFSTR("- value\n")); } // iterate and display all metadata items QTMetaDataItem item = kQTMetaDataItemUninitialized; // Get the next metadata item, regardless of the type of storage format while (noErr == (MDUtils_GetNextItemForAnyStorageFormat(metaDataRef, item, &item))) { DrawStringToFrontWindow(CFSTR("--------------------------------------------\n")); DumpAllPropertiesForMetaDataItem(metaDataRef, item); } // we are done so release our metadata object QTMetaDataRelease(metaDataRef); NILMOVIE: NOMETADATAREF: ; }
/* Initializes the map & targetTrack to receive audio data */ OSStatus initialize_audio_map(NCStream *map, Track targetTrack, Handle dataRef, OSType dataRefType, AVPacket *firstFrame) { Media media; SoundDescriptionHandle sndHdl = NULL; AudioStreamBasicDescription asbd; AVCodecContext *codec; UInt32 ioSize; OSStatus err = noErr; uint8_t *cookie = NULL; size_t cookieSize = 0; codec = map->str->codec; map->base = map->str->time_base; media = NewTrackMedia(targetTrack, SoundMediaType, codec->sample_rate, dataRef, dataRefType); map->media = media; memset(&asbd,0,sizeof(asbd)); map_avi_to_mov_tag(codec->codec_id, &asbd, map, codec->channels); if(asbd.mFormatID == 0) /* no known codec, use the ms tag */ asbd.mFormatID = 'ms\0\0' + codec->codec_tag; /* the number is stored in the last byte => big endian */ /* Ask the AudioToolbox about vbr of the codec */ ioSize = sizeof(UInt32); AudioFormatGetProperty(kAudioFormatProperty_FormatIsVBR, sizeof(AudioStreamBasicDescription), &asbd, &ioSize, &map->vbr); cookie = create_cookie(codec, &cookieSize, asbd.mFormatID, map->vbr); /* Set as much of the AudioStreamBasicDescription as possible. * Then ask the codec to correct it by calling FormatInfo before creating the SoundDescriptionHandle. * FormatInfo is poorly documented and doesn't set much of an example for 3rd party codecs but we can hope * they'll overwrite bad values here. */ asbd.mSampleRate = codec->sample_rate; asbd.mBytesPerPacket = codec->block_align; asbd.mFramesPerPacket = codec->frame_size; asbd.mChannelsPerFrame = codec->channels; asbd.mBitsPerChannel = codec->bits_per_coded_sample; /* ask the toolbox about more information */ ioSize = sizeof(AudioStreamBasicDescription); err = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, cookieSize, cookie, &ioSize, &asbd); // We can't recover from this (FormatInfo resets mFormatID for bad MPEG-4 AOTs) if (!asbd.mFormatID || !asbd.mChannelsPerFrame) { Codecprintf(NULL, "Audio channels or format not set\n"); goto bail; } // We might be able to recover from this (at least try to import the packets) if (err) { Codecprintf(NULL, "AudioFormatGetProperty failed (error %ld / format %lx)\n", err, asbd.mFormatID); err = noErr; } // This needs to be set for playback to work, but 10.4 (+ AppleTV) didn't set it in FormatInfo. // FIXME anything non-zero (like 1) might work here if (!asbd.mFramesPerPacket && asbd.mFormatID == kAudioFormatMPEGLayer3) asbd.mFramesPerPacket = asbd.mSampleRate > 24000 ? 1152 : 576; // if we don't have mBytesPerPacket, we can't import as CBR. Probably should be VBR, and the codec // either lied about kAudioFormatProperty_FormatIsVBR or isn't present if (asbd.mBytesPerPacket == 0) map->vbr = 1; /* If we have vbr audio, the media scale most likely has to be set to the time_base denumerator */ if(map->vbr) { /* if we have mFramesPerPacket, set mBytesPerPacket to 0 as this can cause * errors if set incorrectly. But in vbr, we just need the mFramesPerPacket * value */ if(asbd.mFramesPerPacket) asbd.mBytesPerPacket = 0; SetMediaTimeScale(media, map->str->time_base.den); } if (asbd.mFormatID == kAudioFormatLinearPCM) asbd.mFramesPerPacket = 1; else if (asbd.mBytesPerPacket) { /* FIXME: in the MSADPCM codec, we get a wrong mFramesPerPacket entry because * of the difference in the sample_rate and the time_base denumerator. So we * recalculate here the mFramesPerPacket entry */ /* For calculation, lets assume a packet duration of 1, use ioSize as tmp storage */ ioSize = map->str->time_base.num * codec->sample_rate / map->str->time_base.den; /* downscale to correct bytes_per_packet */ asbd.mFramesPerPacket = ioSize * asbd.mBytesPerPacket / codec->block_align; } AudioChannelLayout acl; int aclSize = 0; //Set this if you intend to use it memset(&acl, 0, sizeof(AudioChannelLayout)); /* We have to parse the format */ int useDefault = 1; if(asbd.mFormatID == kAudioFormatAC3 || asbd.mFormatID == 'ms \0') { QTMetaDataRef trackMetaData; OSStatus error = QTCopyTrackMetaData(targetTrack, &trackMetaData); if(error == noErr) { const char *prop = "Surround"; OSType key = 'name'; QTMetaDataAddItem(trackMetaData, kQTMetaDataStorageFormatUserData, kQTMetaDataKeyFormatUserData, (UInt8 *)&key, sizeof(key), (UInt8 *)prop, strlen(prop), kQTMetaDataTypeUTF8, NULL); QTMetaDataRelease(trackMetaData); } if(parse_ac3_bitstream(&asbd, &acl, firstFrame->data, firstFrame->size)) { useDefault = 0; aclSize = sizeof(AudioChannelLayout); } } if(useDefault && asbd.mChannelsPerFrame > 2) { acl = GetDefaultChannelLayout(&asbd); aclSize = sizeof(AudioChannelLayout); } if (asbd.mSampleRate > 0) { err = QTSoundDescriptionCreate(&asbd, aclSize == 0 ? NULL : &acl, aclSize, cookie, cookieSize, kQTSoundDescriptionKind_Movie_LowestPossibleVersion, &sndHdl); if(err) { fprintf(stderr, "AVI IMPORTER: Error %ld creating the sound description\n", err); goto bail; } } map->sampleHdl = (SampleDescriptionHandle)sndHdl; map->asbd = asbd; bail: if(cookie) av_free(cookie); return err; } /* initialize_audio_map() */