diff --git a/packager/mpd/base/dash_iop_mpd_notifier.cc b/packager/mpd/base/dash_iop_mpd_notifier.cc index f92664bd74..ccd44c6189 100644 --- a/packager/mpd/base/dash_iop_mpd_notifier.cc +++ b/packager/mpd/base/dash_iop_mpd_notifier.cc @@ -74,15 +74,8 @@ bool DashIopMpdNotifier::NotifyNewContainer(const MediaInfo& media_info, return false; base::AutoLock auto_lock(lock_); - std::string lang; - if (media_info.has_audio_info()) { - lang = media_info.audio_info().language(); - } else if (media_info.has_text_info()) { - lang = media_info.text_info().language(); - } - - AdaptationSet* adaptation_set = - GetAdaptationSetForMediaInfo(media_info, content_type, lang); + const std::string key = GetAdaptationSetKey(media_info); + AdaptationSet* adaptation_set = GetAdaptationSetForMediaInfo(key, media_info); DCHECK(adaptation_set); if (media_info.has_text_info()) { // IOP requires all AdaptationSets to have (sub)segmentAlignment set to @@ -100,7 +93,7 @@ bool DashIopMpdNotifier::NotifyNewContainer(const MediaInfo& media_info, representation_id_to_adaptation_set_[representation->id()] = adaptation_set; - SetGroupId(content_type, lang, adaptation_set); + SetGroupId(key, adaptation_set); *container_id = representation->id(); DCHECK(!ContainsKey(representation_map_, representation->id())); @@ -169,13 +162,11 @@ bool DashIopMpdNotifier::Flush() { } AdaptationSet* DashIopMpdNotifier::GetAdaptationSetForMediaInfo( - const MediaInfo& media_info, - ContentType content_type, - const std::string& language) { - std::list& adaptation_sets = - adaptation_set_list_map_[content_type][language]; + const std::string& key, + const MediaInfo& media_info) { + std::list& adaptation_sets = adaptation_set_list_map_[key]; if (adaptation_sets.empty()) - return NewAdaptationSet(media_info, language, &adaptation_sets); + return NewAdaptationSet(media_info, &adaptation_sets); const bool has_protected_content = media_info.has_protected_content(); @@ -204,13 +195,12 @@ AdaptationSet* DashIopMpdNotifier::GetAdaptationSetForMediaInfo( // None of the adaptation sets match with the new content protection. // Need a new one. - return NewAdaptationSet(media_info, language, &adaptation_sets); + return NewAdaptationSet(media_info, &adaptation_sets); } // Get all the UUIDs of the AdaptationSet. If another AdaptationSet has the // same UUIDs then those should be groupable. -void DashIopMpdNotifier::SetGroupId(ContentType type, - const std::string& language, +void DashIopMpdNotifier::SetGroupId(const std::string& key, AdaptationSet* adaptation_set) { if (adaptation_set->Group() >= 0) // @group already assigned. return; @@ -230,7 +220,7 @@ void DashIopMpdNotifier::SetGroupId(ContentType type, GetUUIDs(protected_content_it->second); std::list& same_type_adapatation_sets = - adaptation_set_list_map_[type][language]; + adaptation_set_list_map_[key]; DCHECK(!same_type_adapatation_sets.empty()) << "same_type_adapatation_sets should not be null, it should at least " "contain adaptation_set"; @@ -270,8 +260,8 @@ void DashIopMpdNotifier::SetGroupId(ContentType type, AdaptationSet* DashIopMpdNotifier::NewAdaptationSet( const MediaInfo& media_info, - const std::string& language, std::list* adaptation_sets) { + std::string language = GetLanguage(media_info); AdaptationSet* new_adaptation_set = mpd_builder_->AddAdaptationSet(language); if (media_info.has_protected_content()) { DCHECK(!ContainsKey(protected_content_map_, new_adaptation_set->id())); diff --git a/packager/mpd/base/dash_iop_mpd_notifier.h b/packager/mpd/base/dash_iop_mpd_notifier.h index d4dce450b8..4c534ae572 100644 --- a/packager/mpd/base/dash_iop_mpd_notifier.h +++ b/packager/mpd/base/dash_iop_mpd_notifier.h @@ -70,22 +70,17 @@ class DashIopMpdNotifier : public MpdNotifier { // This does not necessarily return a new AdaptationSet. If // media_info.protected_content completely matches with an existing // AdaptationSet, then it will return the pointer. - AdaptationSet* GetAdaptationSetForMediaInfo(const MediaInfo& media_info, - ContentType type, - const std::string& language); + AdaptationSet* GetAdaptationSetForMediaInfo(const std::string& key, + const MediaInfo& media_info); // Sets a group id for |adaptation_set| if applicable. // If a group ID is already assigned, then this returns immediately. - // |type| and |language| are the type and language of |adaptation_set|. - void SetGroupId(ContentType type, - const std::string& language, - AdaptationSet* adaptation_set); + void SetGroupId(const std::string& key, AdaptationSet* adaptation_set); // Helper function to get a new AdaptationSet; registers the values // to the fields (maps) of the instance. // If the media is encrypted, registers data to protected_content_map_. AdaptationSet* NewAdaptationSet(const MediaInfo& media_info, - const std::string& language, std::list* adaptation_sets); // Testing only method. Returns a pointer to MpdBuilder. @@ -98,10 +93,7 @@ class DashIopMpdNotifier : public MpdNotifier { mpd_builder_ = mpd_builder.Pass(); } - // [type][lang] = list - // Note: lang can be empty, e.g. for video. - std::map > > - adaptation_set_list_map_; + std::map> adaptation_set_list_map_; RepresentationMap representation_map_; // Used to check whether a Representation should be added to an AdaptationSet. diff --git a/packager/mpd/base/dash_iop_mpd_notifier_unittest.cc b/packager/mpd/base/dash_iop_mpd_notifier_unittest.cc index e1d7b6102d..8235b118f0 100644 --- a/packager/mpd/base/dash_iop_mpd_notifier_unittest.cc +++ b/packager/mpd/base/dash_iop_mpd_notifier_unittest.cc @@ -776,6 +776,102 @@ TEST_F(DashIopMpdNotifierTest, NotifyNewContainerAndSampleDurationNoMock) { EXPECT_TRUE(notifier.Flush()); } +// Don't put different audio languages or codecs in the same AdaptationSet. +TEST_P(DashIopMpdNotifierTest, SplitAdaptationSetsByLanguageAndCodec) { + // MP4, English + const char kAudioContent1[] = + "audio_info {\n" + " codec: 'mp4a.40.2'\n" + " sampling_frequency: 44100\n" + " time_scale: 1200\n" + " num_channels: 2\n" + " language: 'eng'\n" + "}\n" + "reference_time_scale: 50\n" + "container_type: CONTAINER_MP4\n" + "media_duration_seconds: 10.5\n"; + + // MP4, German + const char kAudioContent2[] = + "audio_info {\n" + " codec: 'mp4a.40.2'\n" + " sampling_frequency: 44100\n" + " time_scale: 1200\n" + " num_channels: 2\n" + " language: 'ger'\n" + "}\n" + "reference_time_scale: 50\n" + "container_type: CONTAINER_MP4\n" + "media_duration_seconds: 10.5\n"; + + // WebM, German + const char kAudioContent3[] = + "audio_info {\n" + " codec: 'vorbis'\n" + " sampling_frequency: 44100\n" + " time_scale: 1200\n" + " num_channels: 2\n" + " language: 'ger'\n" + "}\n" + "reference_time_scale: 50\n" + "container_type: CONTAINER_WEBM\n" + "media_duration_seconds: 10.5\n"; + + // WebM, German again + const char kAudioContent4[] = + "audio_info {\n" + " codec: 'vorbis'\n" + " sampling_frequency: 44100\n" + " time_scale: 1200\n" + " num_channels: 2\n" + " language: 'ger'\n" + "}\n" + "reference_time_scale: 50\n" + "container_type: CONTAINER_WEBM\n" + "media_duration_seconds: 10.5\n"; + + DashIopMpdNotifier notifier(dash_profile(), empty_mpd_option_, + empty_base_urls_, output_path_); + scoped_ptr mock_mpd_builder(new MockMpdBuilder(mpd_type())); + + scoped_ptr adaptation_set1(new MockAdaptationSet(1)); + scoped_ptr adaptation_set2(new MockAdaptationSet(2)); + scoped_ptr adaptation_set3(new MockAdaptationSet(3)); + + scoped_ptr representation1(new MockRepresentation(1)); + scoped_ptr representation2(new MockRepresentation(2)); + scoped_ptr representation3(new MockRepresentation(3)); + scoped_ptr representation4(new MockRepresentation(4)); + + // We expect three AdaptationSets. + EXPECT_CALL(*mock_mpd_builder, AddAdaptationSet(_)) + .WillOnce(Return(adaptation_set1.get())) + .WillOnce(Return(adaptation_set2.get())) + .WillOnce(Return(adaptation_set3.get())); + // The first AdaptationSet should have Eng MP4, one Representation. + EXPECT_CALL(*adaptation_set1, AddRepresentation(_)) + .WillOnce(Return(representation1.get())); + // The second AdaptationSet should have Ger MP4, one Representation. + EXPECT_CALL(*adaptation_set2, AddRepresentation(_)) + .WillOnce(Return(representation2.get())); + // The third AdaptationSet should have Ger WebM, two Representations. + EXPECT_CALL(*adaptation_set3, AddRepresentation(_)) + .WillOnce(Return(representation3.get())) + .WillOnce(Return(representation4.get())); + + uint32_t unused_container_id; + SetMpdBuilder(¬ifier, mock_mpd_builder.Pass()); + EXPECT_TRUE(notifier.NotifyNewContainer( + ConvertToMediaInfo(kAudioContent1), &unused_container_id)); + EXPECT_TRUE(notifier.NotifyNewContainer( + ConvertToMediaInfo(kAudioContent2), &unused_container_id)); + EXPECT_TRUE(notifier.NotifyNewContainer( + ConvertToMediaInfo(kAudioContent3), &unused_container_id)); + EXPECT_TRUE(notifier.NotifyNewContainer( + ConvertToMediaInfo(kAudioContent4), &unused_container_id)); +} + + INSTANTIATE_TEST_CASE_P(StaticAndDynamic, DashIopMpdNotifierTest, ::testing::Values(MpdBuilder::kStatic, diff --git a/packager/mpd/base/mpd_utils.cc b/packager/mpd/base/mpd_utils.cc index 893a262d00..99b576fc12 100644 --- a/packager/mpd/base/mpd_utils.cc +++ b/packager/mpd/base/mpd_utils.cc @@ -57,6 +57,16 @@ void RemoveDuplicateAttributes( attributes.erase("schemeIdUri"); } +std::string GetLanguage(const MediaInfo& media_info) { + std::string lang; + if (media_info.has_audio_info()) { + lang = media_info.audio_info().language(); + } else if (media_info.has_text_info()) { + lang = media_info.text_info().language(); + } + return lang; +} + std::string GetCodecs(const MediaInfo& media_info) { CHECK(OnlyOneTrue(media_info.has_video_info(), media_info.has_audio_info(), media_info.has_text_info())); @@ -86,6 +96,47 @@ std::string GetCodecs(const MediaInfo& media_info) { return ""; } +std::string GetBaseCodec(const MediaInfo& media_info) { + std::string codec; + if (media_info.has_video_info()) { + codec = media_info.video_info().codec(); + } else if (media_info.has_audio_info()) { + codec = media_info.audio_info().codec(); + } else if (media_info.has_text_info()) { + codec = media_info.text_info().format(); + } + // Convert, for example, "mp4a.40.2" to simply "mp4a". + // "mp4a.40.2" and "mp4a.40.5" can exist in the same AdaptationSet. + size_t dot = codec.find('.'); + if (dot != std::string::npos) { + codec.erase(dot); + } + return codec; +} + +std::string GetAdaptationSetKey(const MediaInfo& media_info) { + std::string key; + + if (media_info.has_video_info()) { + key.append("video:"); + } else if (media_info.has_audio_info()) { + key.append("audio:"); + } else if (media_info.has_text_info()) { + key.append(MediaInfo_TextInfo_TextType_Name(media_info.text_info().type())); + key.append(":"); + } else { + key.append("unknown:"); + } + + key.append(MediaInfo_ContainerType_Name(media_info.container_type())); + key.append(":"); + key.append(GetBaseCodec(media_info)); + key.append(":"); + key.append(GetLanguage(media_info)); + + return key; +} + std::string SecondsToXmlDuration(double seconds) { return "PT" + base::DoubleToString(seconds) + "S"; } diff --git a/packager/mpd/base/mpd_utils.h b/packager/mpd/base/mpd_utils.h index 50d8268e5e..970e17730f 100644 --- a/packager/mpd/base/mpd_utils.h +++ b/packager/mpd/base/mpd_utils.h @@ -40,10 +40,20 @@ bool HasLiveOnlyFields(const MediaInfo& media_info); void RemoveDuplicateAttributes( ContentProtectionElement* content_protection_element); +// Returns a language tag. May be blank for video. +std::string GetLanguage(const MediaInfo& media_info); + // Returns a 'codecs' string that has all the video and audio codecs joined with // comma. std::string GetCodecs(const MediaInfo& media_info); +// Returns a codec string without variants. For example, "mp4a" instead of +// "mp4a.40.2". May return a format for text streams. +std::string GetBaseCodec(const MediaInfo& media_info); + +// Returns a key made from the characteristics that separate AdaptationSets. +std::string GetAdaptationSetKey(const MediaInfo& media_info); + std::string SecondsToXmlDuration(double seconds); // Tries to get "duration" attribute from |node|. On success |duration| is set. diff --git a/packager/mpd/base/simple_mpd_notifier.cc b/packager/mpd/base/simple_mpd_notifier.cc index 4049a33af6..a54e35f352 100644 --- a/packager/mpd/base/simple_mpd_notifier.cc +++ b/packager/mpd/base/simple_mpd_notifier.cc @@ -44,15 +44,12 @@ bool SimpleMpdNotifier::NotifyNewContainer(const MediaInfo& media_info, return false; base::AutoLock auto_lock(lock_); + // TODO(kqyang): Consider adding a new method MpdBuilder::AddRepresentation. // Most of the codes here can be moved inside. - std::string lang; - if (media_info.has_audio_info()) { - lang = media_info.audio_info().language(); - } else if (media_info.has_text_info()) { - lang = media_info.text_info().language(); - } - AdaptationSet** adaptation_set = &adaptation_set_map_[content_type][lang]; + std::string key = GetAdaptationSetKey(media_info); + std::string lang = GetLanguage(media_info); + AdaptationSet** adaptation_set = &adaptation_set_map_[key]; if (*adaptation_set == NULL) *adaptation_set = mpd_builder_->AddAdaptationSet(lang); diff --git a/packager/mpd/base/simple_mpd_notifier.h b/packager/mpd/base/simple_mpd_notifier.h index 6eb8575c7e..d8cf2c6ce9 100644 --- a/packager/mpd/base/simple_mpd_notifier.h +++ b/packager/mpd/base/simple_mpd_notifier.h @@ -74,9 +74,7 @@ class SimpleMpdNotifier : public MpdNotifier { scoped_ptr mpd_builder_; base::Lock lock_; - // [type][lang] = AdaptationSet - typedef std::map > - AdaptationSetMap; + typedef std::map AdaptationSetMap; AdaptationSetMap adaptation_set_map_; typedef std::map RepresentationMap; diff --git a/packager/mpd/base/simple_mpd_notifier_unittest.cc b/packager/mpd/base/simple_mpd_notifier_unittest.cc index fa4deceb9a..e34b04c219 100644 --- a/packager/mpd/base/simple_mpd_notifier_unittest.cc +++ b/packager/mpd/base/simple_mpd_notifier_unittest.cc @@ -308,6 +308,101 @@ TEST_P(SimpleMpdNotifierTest, UpdateEncryption) { container_id, "myuuid", std::vector(), kBogusNewPsshVector)); } +// Don't put different audio languages or codecs in the same AdaptationSet. +TEST_P(SimpleMpdNotifierTest, SplitAdaptationSetsByLanguageAndCodec) { + // MP4, English + const char kAudioContent1[] = + "audio_info {\n" + " codec: 'mp4a.40.2'\n" + " sampling_frequency: 44100\n" + " time_scale: 1200\n" + " num_channels: 2\n" + " language: 'eng'\n" + "}\n" + "reference_time_scale: 50\n" + "container_type: CONTAINER_MP4\n" + "media_duration_seconds: 10.5\n"; + + // MP4, German + const char kAudioContent2[] = + "audio_info {\n" + " codec: 'mp4a.40.2'\n" + " sampling_frequency: 44100\n" + " time_scale: 1200\n" + " num_channels: 2\n" + " language: 'ger'\n" + "}\n" + "reference_time_scale: 50\n" + "container_type: CONTAINER_MP4\n" + "media_duration_seconds: 10.5\n"; + + // WebM, German + const char kAudioContent3[] = + "audio_info {\n" + " codec: 'vorbis'\n" + " sampling_frequency: 44100\n" + " time_scale: 1200\n" + " num_channels: 2\n" + " language: 'ger'\n" + "}\n" + "reference_time_scale: 50\n" + "container_type: CONTAINER_WEBM\n" + "media_duration_seconds: 10.5\n"; + + // WebM, German again + const char kAudioContent4[] = + "audio_info {\n" + " codec: 'vorbis'\n" + " sampling_frequency: 44100\n" + " time_scale: 1200\n" + " num_channels: 2\n" + " language: 'ger'\n" + "}\n" + "reference_time_scale: 50\n" + "container_type: CONTAINER_WEBM\n" + "media_duration_seconds: 10.5\n"; + + SimpleMpdNotifier notifier(kOnDemandProfile, empty_mpd_option_, + empty_base_urls_, output_path_); + scoped_ptr mock_mpd_builder(StaticMpdBuilderMock()); + + scoped_ptr adaptation_set1(new MockAdaptationSet(1)); + scoped_ptr adaptation_set2(new MockAdaptationSet(2)); + scoped_ptr adaptation_set3(new MockAdaptationSet(3)); + + scoped_ptr representation1(new MockRepresentation(1)); + scoped_ptr representation2(new MockRepresentation(2)); + scoped_ptr representation3(new MockRepresentation(3)); + scoped_ptr representation4(new MockRepresentation(4)); + + // We expect three AdaptationSets. + EXPECT_CALL(*mock_mpd_builder, AddAdaptationSet(_)) + .WillOnce(Return(adaptation_set1.get())) + .WillOnce(Return(adaptation_set2.get())) + .WillOnce(Return(adaptation_set3.get())); + // The first AdaptationSet should have Eng MP4, one Representation. + EXPECT_CALL(*adaptation_set1, AddRepresentation(_)) + .WillOnce(Return(representation1.get())); + // The second AdaptationSet should have Ger MP4, one Representation. + EXPECT_CALL(*adaptation_set2, AddRepresentation(_)) + .WillOnce(Return(representation2.get())); + // The third AdaptationSet should have Ger WebM, two Representations. + EXPECT_CALL(*adaptation_set3, AddRepresentation(_)) + .WillOnce(Return(representation3.get())) + .WillOnce(Return(representation4.get())); + + uint32_t unused_container_id; + SetMpdBuilder(¬ifier, mock_mpd_builder.Pass()); + EXPECT_TRUE(notifier.NotifyNewContainer( + ConvertToMediaInfo(kAudioContent1), &unused_container_id)); + EXPECT_TRUE(notifier.NotifyNewContainer( + ConvertToMediaInfo(kAudioContent2), &unused_container_id)); + EXPECT_TRUE(notifier.NotifyNewContainer( + ConvertToMediaInfo(kAudioContent3), &unused_container_id)); + EXPECT_TRUE(notifier.NotifyNewContainer( + ConvertToMediaInfo(kAudioContent4), &unused_container_id)); +} + INSTANTIATE_TEST_CASE_P(StaticAndDynamic, SimpleMpdNotifierTest, ::testing::Values(MpdBuilder::kStatic, diff --git a/packager/mpd/test/data/language_audio_media_info1.txt b/packager/mpd/test/data/language_audio_media_info1.txt deleted file mode 100644 index 568d1c020a..0000000000 --- a/packager/mpd/test/data/language_audio_media_info1.txt +++ /dev/null @@ -1,20 +0,0 @@ -bandwidth: 400 -audio_info { - codec: "mp4a.40.2" - sampling_frequency: 44100 - time_scale: 1200 - num_channels: 2 - language: "eng" -} -init_range { - begin: 0 - end: 120 -} -index_range { - begin: 121 - end: 221 -} -reference_time_scale: 50 -container_type: 1 -media_file_name: "test_output_file_name_audio_eng1.mp4" -media_duration_seconds: 10.5 diff --git a/packager/mpd/test/data/language_audio_media_info2.txt b/packager/mpd/test/data/language_audio_media_info2.txt deleted file mode 100644 index b59a7da75b..0000000000 --- a/packager/mpd/test/data/language_audio_media_info2.txt +++ /dev/null @@ -1,20 +0,0 @@ -bandwidth: 800 -audio_info { - codec: "mp4a.40.2" - sampling_frequency: 44100 - time_scale: 1200 - num_channels: 2 - language: "eng" -} -init_range { - begin: 0 - end: 120 -} -index_range { - begin: 121 - end: 221 -} -reference_time_scale: 50 -container_type: 1 -media_file_name: "test_output_file_name_audio_eng2.mp4" -media_duration_seconds: 10.5 diff --git a/packager/mpd/test/data/language_audio_media_info3.txt b/packager/mpd/test/data/language_audio_media_info3.txt deleted file mode 100644 index 07563cd5ca..0000000000 --- a/packager/mpd/test/data/language_audio_media_info3.txt +++ /dev/null @@ -1,20 +0,0 @@ -bandwidth: 400 -audio_info { - codec: "mp4a.40.2" - sampling_frequency: 44100 - time_scale: 1200 - num_channels: 2 - language: "ger" -} -init_range { - begin: 0 - end: 120 -} -index_range { - begin: 121 - end: 221 -} -reference_time_scale: 50 -container_type: 1 -media_file_name: "test_output_file_name_audio_ger1.mp4" -media_duration_seconds: 10.5 diff --git a/packager/mpd/test/data/language_audio_media_info_expected_output.txt b/packager/mpd/test/data/language_audio_media_info_expected_output.txt deleted file mode 100644 index 68dd6b8afc..0000000000 --- a/packager/mpd/test/data/language_audio_media_info_expected_output.txt +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - test_output_file_name1.mp4 - - - - - - - - - test_output_file_name_audio_eng1.mp4 - - - - - - - test_output_file_name_audio_eng2.mp4 - - - - - - - - - test_output_file_name_audio_ger1.mp4 - - - - - - - diff --git a/packager/mpd/test/data/language_video_media_info1.txt b/packager/mpd/test/data/language_video_media_info1.txt deleted file mode 100644 index 02477f06bc..0000000000 --- a/packager/mpd/test/data/language_video_media_info1.txt +++ /dev/null @@ -1,22 +0,0 @@ -bandwidth: 7620 -video_info { - codec: "avc1.010101" - width: 720 - height: 480 - time_scale: 10 - frame_duration: 1 - pixel_width: 1 - pixel_height: 1 -} -init_range { - begin: 0 - end: 120 -} -index_range { - begin: 121 - end: 221 -} -reference_time_scale: 1000 -container_type: 1 -media_file_name: "test_output_file_name1.mp4" -media_duration_seconds: 10.5 diff --git a/packager/mpd/test/mpd_builder_test_helper.h b/packager/mpd/test/mpd_builder_test_helper.h index b216704fd6..e2842ad6bb 100644 --- a/packager/mpd/test/mpd_builder_test_helper.h +++ b/packager/mpd/test/mpd_builder_test_helper.h @@ -23,14 +23,6 @@ const char kFileNameVideoMediaInfo1[] = "video_media_info1.txt"; const char kFileNameVideoMediaInfo2[] = "video_media_info2.txt"; const char kFileNameAudioMediaInfo1[] = "audio_media_info1.txt"; const char kFileNameEncytpedAudioMediaInfo[] = "encrypted_audio_media_info.txt"; -const char kFileNameLanguageAudioMediaInfo1[] = - "language_audio_media_info1.txt"; -const char kFileNameLanguageAudioMediaInfo2[] = - "language_audio_media_info2.txt"; -const char kFileNameLanguageAudioMediaInfo3[] = - "language_audio_media_info3.txt"; -const char kFileNameLanguageVideoMediaInfo1[] = - "language_video_media_info1.txt"; // These are the expected output files. const char kFileNameExpectedMpdOutputVideo1[] = @@ -50,9 +42,6 @@ const char kFileNameExpectedMpdOutputEncryptedAudio[] = const char kFileNameExpectedMpdOutputDynamicNormal[] = "dynamic_normal_mpd.txt"; -const char kFileNameExpectedMpdOutputLanguageAudio[] = - "language_audio_media_info_expected_output.txt"; - // Returns the path to test data with |file_name|. Use constants above to get // path to the test files. base::FilePath GetTestDataFilePath(const std::string& file_name);