1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file. 4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/utility/media_galleries/media_metadata_parser.h" 6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/bind.h" 100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/memory/linked_ptr.h" 11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/message_loop/message_loop.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_util.h" 13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/task_runner_util.h" 14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/threading/thread.h" 15a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "chrome/utility/media_galleries/image_metadata_extractor.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/audio_video_metadata_extractor.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/data_source.h" 18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/base/mime_sniffer.h" 19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochnamespace MediaGalleries = extensions::api::media_galleries; 210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace metadata { 23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SetStringScopedPtr(const std::string& value, 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<std::string>* destination) { 28a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DCHECK(destination); 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!value.empty()) 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) destination->reset(new std::string(value)); 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void SetIntScopedPtr(int value, scoped_ptr<int>* destination) { 34a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DCHECK(destination); 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (value >= 0) 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) destination->reset(new int(value)); 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 39a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid SetDoubleScopedPtr(double value, scoped_ptr<double>* destination) { 40a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DCHECK(destination); 41a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (value >= 0) 42a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch destination->reset(new double(value)); 43a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 44a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 45a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid SetBoolScopedPtr(bool value, scoped_ptr<bool>* destination) { 46a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DCHECK(destination); 47a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch destination->reset(new bool(value)); 48a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 49a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// This runs on |media_thread_|, as the underlying FFmpeg operation is 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// blocking, and the utility thread must not be blocked, so the media file 52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// bytes can be sent from the browser process to the utility process. 53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ParseAudioVideoMetadata( 54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media::DataSource* source, bool get_attached_images, 55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MediaMetadataParser::MediaMetadata* metadata, 56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<AttachedImage>* attached_images) { 57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DCHECK(source); 58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(metadata); 59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) media::AudioVideoMetadataExtractor extractor; 60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (!extractor.Extract(source, get_attached_images)) 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (extractor.duration() >= 0) 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) metadata->duration.reset(new double(extractor.duration())); 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (extractor.height() >= 0 && extractor.width() >= 0) { 68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) metadata->height.reset(new int(extractor.height())); 69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) metadata->width.reset(new int(extractor.width())); 70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) } 71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetStringScopedPtr(extractor.artist(), &metadata->artist); 73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetStringScopedPtr(extractor.album(), &metadata->album); 74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetStringScopedPtr(extractor.artist(), &metadata->artist); 75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetStringScopedPtr(extractor.comment(), &metadata->comment); 76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetStringScopedPtr(extractor.copyright(), &metadata->copyright); 77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetIntScopedPtr(extractor.disc(), &metadata->disc); 78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetStringScopedPtr(extractor.genre(), &metadata->genre); 79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetStringScopedPtr(extractor.language(), &metadata->language); 80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetIntScopedPtr(extractor.rotation(), &metadata->rotation); 81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetStringScopedPtr(extractor.title(), &metadata->title); 82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) SetIntScopedPtr(extractor.track(), &metadata->track); 83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch for (media::AudioVideoMetadataExtractor::StreamInfoVector::const_iterator it = 850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch extractor.stream_infos().begin(); 860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch it != extractor.stream_infos().end(); ++it) { 870529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch linked_ptr<MediaGalleries::StreamInfo> stream_info( 880529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch new MediaGalleries::StreamInfo); 890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch stream_info->type = it->type; 900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch for (std::map<std::string, std::string>::const_iterator tag_it = 920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch it->tags.begin(); 930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch tag_it != it->tags.end(); ++tag_it) { 940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch stream_info->tags.additional_properties.SetString(tag_it->first, 950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch tag_it->second); 960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch 980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch metadata->raw_tags.push_back(stream_info); 99c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch } 100c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (get_attached_images) { 102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (std::vector<std::string>::const_iterator it = 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extractor.attached_images_bytes().begin(); 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) it != extractor.attached_images_bytes().end(); ++it) { 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) attached_images->push_back(AttachedImage()); 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) attached_images->back().data = *it; 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) net::SniffMimeTypeFromLocalData(it->c_str(), it->length(), 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &attached_images->back().type); 109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FinishParseAudioVideoMetadata( 114a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch MediaMetadataParser::MetadataCallback callback, 115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MediaMetadataParser::MediaMetadata* metadata, 116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<AttachedImage>* attached_images) { 117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(!callback.is_null()); 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(metadata); 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(attached_images); 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback.Run(*metadata, *attached_images); 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void FinishParseImageMetadata( 125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ImageMetadataExtractor* extractor, const std::string& mime_type, 126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MediaMetadataParser::MetadataCallback callback, bool extract_success) { 127a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch DCHECK(extractor); 128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MediaMetadataParser::MediaMetadata metadata; 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) metadata.mime_type = mime_type; 130a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 131a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (!extract_success) { 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback.Run(metadata, std::vector<AttachedImage>()); 133a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return; 134a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 135a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetIntScopedPtr(extractor->height(), &metadata.height); 137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetIntScopedPtr(extractor->width(), &metadata.width); 138a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetIntScopedPtr(extractor->rotation(), &metadata.rotation); 140a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetDoubleScopedPtr(extractor->x_resolution(), &metadata.x_resolution); 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetDoubleScopedPtr(extractor->y_resolution(), &metadata.y_resolution); 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetBoolScopedPtr(extractor->flash_fired(), &metadata.flash_fired); 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetStringScopedPtr(extractor->camera_make(), &metadata.camera_make); 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetStringScopedPtr(extractor->camera_model(), &metadata.camera_model); 146a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch SetDoubleScopedPtr(extractor->exposure_time_sec(), 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &metadata.exposure_time_seconds); 148a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetDoubleScopedPtr(extractor->f_number(), &metadata.f_number); 150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetDoubleScopedPtr(extractor->focal_length_mm(), &metadata.focal_length_mm); 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SetDoubleScopedPtr(extractor->iso_equivalent(), &metadata.iso_equivalent); 152a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback.Run(metadata, std::vector<AttachedImage>()); 154a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 155a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MediaMetadataParser::MediaMetadataParser(media::DataSource* source, 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& mime_type, 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool get_attached_images) 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : source_(source), 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mime_type_(mime_type), 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) get_attached_images_(get_attached_images) { 164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)MediaMetadataParser::~MediaMetadataParser() {} 167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void MediaMetadataParser::Start(const MetadataCallback& callback) { 169a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (StartsWithASCII(mime_type_, "audio/", true) || 170a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) StartsWithASCII(mime_type_, "video/", true)) { 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) MediaMetadata* metadata = new MediaMetadata; 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) metadata->mime_type = mime_type_; 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::vector<AttachedImage>* attached_images = 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new std::vector<AttachedImage>; 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 176a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) media_thread_.reset(new base::Thread("media_thread")); 177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) CHECK(media_thread_->Start()); 178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) media_thread_->message_loop_proxy()->PostTaskAndReply( 179a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FROM_HERE, 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&ParseAudioVideoMetadata, source_, get_attached_images_, 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) metadata, attached_images), 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&FinishParseAudioVideoMetadata, callback, 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Owned(metadata), base::Owned(attached_images))); 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 187a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (StartsWithASCII(mime_type_, "image/", true)) { 188a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch ImageMetadataExtractor* extractor = new ImageMetadataExtractor; 189a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch extractor->Extract( 190a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch source_, 191a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch base::Bind(&FinishParseImageMetadata, base::Owned(extractor), 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) mime_type_, callback)); 193a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch return; 194a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 195a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback.Run(MediaMetadata(), std::vector<AttachedImage>()); 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace metadata 200