Added stream descriptor for output format.
Added two stream descriptors that are both used to tell the output format. If it is not given, the packager will use the output file extension to determine the output format. Change-Id: Ib8d5dcf52956c2d451e77ea6a90d9502d4a77064
This commit is contained in:
parent
af7d6a7921
commit
05f5682728
|
@ -19,7 +19,6 @@
|
||||||
#include "packager/base/logging.h"
|
#include "packager/base/logging.h"
|
||||||
#include "packager/base/stl_util.h"
|
#include "packager/base/stl_util.h"
|
||||||
#include "packager/base/strings/string_split.h"
|
#include "packager/base/strings/string_split.h"
|
||||||
#include "packager/base/strings/string_util.h"
|
|
||||||
#include "packager/base/strings/stringprintf.h"
|
#include "packager/base/strings/stringprintf.h"
|
||||||
#include "packager/base/threading/simple_thread.h"
|
#include "packager/base/threading/simple_thread.h"
|
||||||
#include "packager/base/time/clock.h"
|
#include "packager/base/time/clock.h"
|
||||||
|
@ -67,7 +66,10 @@ const char kUsage[] =
|
||||||
"If not specified, its value may be estimated.\n"
|
"If not specified, its value may be estimated.\n"
|
||||||
" - language (lang): Optional value which contains a user-specified "
|
" - language (lang): Optional value which contains a user-specified "
|
||||||
"language tag. If specified, this value overrides any language metadata "
|
"language tag. If specified, this value overrides any language metadata "
|
||||||
"in the input track.\n";
|
"in the input track.\n"
|
||||||
|
" - output_format (format): Optional value which specifies the format "
|
||||||
|
"of the output files (MP4 or WebM). If not specified, it will be "
|
||||||
|
"derived from the file extension of the output file.\n";
|
||||||
|
|
||||||
const char kMediaInfoSuffix[] = ".media_info";
|
const char kMediaInfoSuffix[] = ".media_info";
|
||||||
|
|
||||||
|
@ -183,22 +185,13 @@ bool StreamInfoToTextMediaInfo(const StreamDescriptor& stream_descriptor,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
scoped_ptr<Muxer> CreateOutputMuxer(const MuxerOptions& options) {
|
scoped_ptr<Muxer> CreateOutputMuxer(const MuxerOptions& options,
|
||||||
// TODO(modmaker): Add a config option for output format
|
MediaContainerName container) {
|
||||||
const std::string& file_name = options.output_file_name;
|
if (container == CONTAINER_WEBM) {
|
||||||
if (base::EndsWith(file_name, ".webm",
|
|
||||||
base::CompareCase::INSENSITIVE_ASCII)) {
|
|
||||||
return scoped_ptr<Muxer>(new webm::WebMMuxer(options));
|
return scoped_ptr<Muxer>(new webm::WebMMuxer(options));
|
||||||
} else if (base::EndsWith(file_name, ".mp4",
|
|
||||||
base::CompareCase::INSENSITIVE_ASCII) ||
|
|
||||||
base::EndsWith(file_name, ".m4a",
|
|
||||||
base::CompareCase::INSENSITIVE_ASCII) ||
|
|
||||||
base::EndsWith(file_name, ".m4v",
|
|
||||||
base::CompareCase::INSENSITIVE_ASCII)) {
|
|
||||||
return scoped_ptr<Muxer>(new mp4::MP4Muxer(options));
|
|
||||||
} else {
|
} else {
|
||||||
LOG(ERROR) << "Unrecognized output format " << file_name;
|
DCHECK_EQ(container, CONTAINER_MOV);
|
||||||
return NULL;
|
return scoped_ptr<Muxer>(new mp4::MP4Muxer(options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,9 +275,20 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
||||||
}
|
}
|
||||||
DCHECK(!remux_jobs->empty());
|
DCHECK(!remux_jobs->empty());
|
||||||
|
|
||||||
scoped_ptr<Muxer> muxer(CreateOutputMuxer(stream_muxer_options));
|
MediaContainerName output_format = stream_iter->output_format;
|
||||||
if (!muxer)
|
if (output_format == CONTAINER_UNKNOWN) {
|
||||||
|
output_format =
|
||||||
|
DetermineContainerFromFileName(stream_muxer_options.output_file_name);
|
||||||
|
|
||||||
|
if (output_format == CONTAINER_UNKNOWN) {
|
||||||
|
LOG(ERROR) << "Unable to determine output format for file "
|
||||||
|
<< stream_muxer_options.output_file_name;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scoped_ptr<Muxer> muxer(
|
||||||
|
CreateOutputMuxer(stream_muxer_options, output_format));
|
||||||
if (FLAGS_use_fake_clock_for_muxer) muxer->set_clock(fake_clock);
|
if (FLAGS_use_fake_clock_for_muxer) muxer->set_clock(fake_clock);
|
||||||
|
|
||||||
if (key_source) {
|
if (key_source) {
|
||||||
|
|
|
@ -25,6 +25,7 @@ enum FieldType {
|
||||||
kSegmentTemplateField,
|
kSegmentTemplateField,
|
||||||
kBandwidthField,
|
kBandwidthField,
|
||||||
kLanguageField,
|
kLanguageField,
|
||||||
|
kOutputFormatField,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FieldNameToTypeMapping {
|
struct FieldNameToTypeMapping {
|
||||||
|
@ -47,6 +48,8 @@ const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
|
||||||
{ "bitrate", kBandwidthField },
|
{ "bitrate", kBandwidthField },
|
||||||
{ "language", kLanguageField },
|
{ "language", kLanguageField },
|
||||||
{ "lang", kLanguageField },
|
{ "lang", kLanguageField },
|
||||||
|
{ "output_format", kOutputFormatField },
|
||||||
|
{ "format", kOutputFormatField },
|
||||||
};
|
};
|
||||||
|
|
||||||
FieldType GetFieldType(const std::string& field_name) {
|
FieldType GetFieldType(const std::string& field_name) {
|
||||||
|
@ -59,7 +62,8 @@ FieldType GetFieldType(const std::string& field_name) {
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
StreamDescriptor::StreamDescriptor() : bandwidth(0) {}
|
StreamDescriptor::StreamDescriptor()
|
||||||
|
: bandwidth(0), output_format(CONTAINER_UNKNOWN) {}
|
||||||
|
|
||||||
StreamDescriptor::~StreamDescriptor() {}
|
StreamDescriptor::~StreamDescriptor() {}
|
||||||
|
|
||||||
|
@ -110,6 +114,16 @@ bool InsertStreamDescriptor(const std::string& descriptor_string,
|
||||||
descriptor.language = language;
|
descriptor.language = language;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case kOutputFormatField: {
|
||||||
|
MediaContainerName output_format =
|
||||||
|
DetermineContainerFromFormatName(iter->second);
|
||||||
|
if (output_format == CONTAINER_UNKNOWN) {
|
||||||
|
LOG(ERROR) << "Unrecognized output format " << iter->second;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
descriptor.output_format = output_format;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
LOG(ERROR) << "Unknown field in stream descriptor (\"" << iter->first
|
LOG(ERROR) << "Unknown field in stream descriptor (\"" << iter->first
|
||||||
<< "\").";
|
<< "\").";
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "media/base/container_names.h"
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
|
@ -27,6 +29,7 @@ struct StreamDescriptor {
|
||||||
std::string segment_template;
|
std::string segment_template;
|
||||||
uint32_t bandwidth;
|
uint32_t bandwidth;
|
||||||
std::string language;
|
std::string language;
|
||||||
|
MediaContainerName output_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StreamDescriptorCompareFn {
|
class StreamDescriptorCompareFn {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
#include "packager/base/logging.h"
|
#include "packager/base/logging.h"
|
||||||
|
#include "packager/base/strings/string_util.h"
|
||||||
#include "packager/media/base/bit_reader.h"
|
#include "packager/media/base/bit_reader.h"
|
||||||
#include "packager/mpd/base/xml/scoped_xml_ptr.h"
|
#include "packager/mpd/base/xml/scoped_xml_ptr.h"
|
||||||
|
|
||||||
|
@ -1714,5 +1715,36 @@ MediaContainerName DetermineContainer(const uint8_t* buffer, int buffer_size) {
|
||||||
return CONTAINER_UNKNOWN;
|
return CONTAINER_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MediaContainerName DetermineContainerFromFormatName(
|
||||||
|
const std::string& format_name) {
|
||||||
|
if (base::EqualsCaseInsensitiveASCII(format_name, "webm")) {
|
||||||
|
return CONTAINER_WEBM;
|
||||||
|
} else if (base::EqualsCaseInsensitiveASCII(format_name, "m4a") ||
|
||||||
|
base::EqualsCaseInsensitiveASCII(format_name, "m4v") ||
|
||||||
|
base::EqualsCaseInsensitiveASCII(format_name, "mp4") ||
|
||||||
|
base::EqualsCaseInsensitiveASCII(format_name, "mov")) {
|
||||||
|
return CONTAINER_MOV;
|
||||||
|
} else {
|
||||||
|
return CONTAINER_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaContainerName DetermineContainerFromFileName(
|
||||||
|
const std::string& file_name) {
|
||||||
|
if (base::EndsWith(file_name, ".webm",
|
||||||
|
base::CompareCase::INSENSITIVE_ASCII)) {
|
||||||
|
return CONTAINER_WEBM;
|
||||||
|
} else if (base::EndsWith(file_name, ".mp4",
|
||||||
|
base::CompareCase::INSENSITIVE_ASCII) ||
|
||||||
|
base::EndsWith(file_name, ".m4a",
|
||||||
|
base::CompareCase::INSENSITIVE_ASCII) ||
|
||||||
|
base::EndsWith(file_name, ".m4v",
|
||||||
|
base::CompareCase::INSENSITIVE_ASCII)) {
|
||||||
|
return CONTAINER_MOV;
|
||||||
|
} else {
|
||||||
|
return CONTAINER_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
|
@ -56,9 +58,18 @@ enum MediaContainerName {
|
||||||
CONTAINER_MAX // Must be last
|
CONTAINER_MAX // Must be last
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Determine the container type.
|
/// Determine the container type from input data.
|
||||||
MediaContainerName DetermineContainer(const uint8_t* buffer, int buffer_size);
|
MediaContainerName DetermineContainer(const uint8_t* buffer, int buffer_size);
|
||||||
|
|
||||||
|
/// Determine the container type from the format name.
|
||||||
|
/// @param format_name Specifies the format, e.g. 'webm', 'mov', 'mp4'.
|
||||||
|
MediaContainerName DetermineContainerFromFormatName(
|
||||||
|
const std::string& format_name);
|
||||||
|
|
||||||
|
/// Determine the container type from the file extension.
|
||||||
|
/// @param file_name Specifies the file name, e.g. 'file.webm', 'video.mp4'.
|
||||||
|
MediaContainerName DetermineContainerFromFileName(const std::string& file_name);
|
||||||
|
|
||||||
} // namespace media
|
} // namespace media
|
||||||
} // namespace edash_packager
|
} // namespace edash_packager
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,35 @@ uint8_t kBug263073Buffer[] = {
|
||||||
0x67, 0x64, 0x00, 0x28, 0xac, 0x2c, 0xa4, 0x01, 0xe0, 0x08, 0x9f,
|
0x67, 0x64, 0x00, 0x28, 0xac, 0x2c, 0xa4, 0x01, 0xe0, 0x08, 0x9f,
|
||||||
0x97, 0x01, 0x52, 0x02, 0x02, 0x02, 0x80, 0x00, 0x01};
|
0x97, 0x01, 0x52, 0x02, 0x02, 0x02, 0x80, 0x00, 0x01};
|
||||||
|
|
||||||
|
TEST(ContainerNamesTest, FromFormatName) {
|
||||||
|
EXPECT_EQ(CONTAINER_WEBM, DetermineContainerFromFormatName("webm"));
|
||||||
|
EXPECT_EQ(CONTAINER_WEBM, DetermineContainerFromFormatName("WeBm"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFormatName("m4a"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFormatName("m4v"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFormatName("M4v"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFormatName("mov"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFormatName("mp4"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFormatName("Mp4"));
|
||||||
|
EXPECT_EQ(CONTAINER_UNKNOWN, DetermineContainerFromFormatName("cat"));
|
||||||
|
EXPECT_EQ(CONTAINER_UNKNOWN, DetermineContainerFromFormatName("amp4"));
|
||||||
|
EXPECT_EQ(CONTAINER_UNKNOWN, DetermineContainerFromFormatName(" mp4"));
|
||||||
|
EXPECT_EQ(CONTAINER_UNKNOWN, DetermineContainerFromFormatName(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ContainerNamesTest, FromFileName) {
|
||||||
|
EXPECT_EQ(CONTAINER_WEBM, DetermineContainerFromFileName("test.webm"));
|
||||||
|
EXPECT_EQ(CONTAINER_WEBM, DetermineContainerFromFileName("another.wEbM"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFileName("test.m4a"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFileName("file.m4v"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFileName("a file .m4V"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFileName("2_more-files.mp4"));
|
||||||
|
EXPECT_EQ(CONTAINER_MOV, DetermineContainerFromFileName("foo.bar.MP4"));
|
||||||
|
EXPECT_EQ(CONTAINER_UNKNOWN, DetermineContainerFromFileName("a_bad.gif"));
|
||||||
|
EXPECT_EQ(CONTAINER_UNKNOWN, DetermineContainerFromFileName("a bad.m4v-"));
|
||||||
|
EXPECT_EQ(CONTAINER_UNKNOWN, DetermineContainerFromFileName("a.m4v."));
|
||||||
|
EXPECT_EQ(CONTAINER_UNKNOWN, DetermineContainerFromFileName(""));
|
||||||
|
}
|
||||||
|
|
||||||
// Test that containers that start with fixed strings are handled correctly.
|
// Test that containers that start with fixed strings are handled correctly.
|
||||||
// This is to verify that the TAG matches the first 4 characters of the string.
|
// This is to verify that the TAG matches the first 4 characters of the string.
|
||||||
TEST(ContainerNamesTest, CheckFixedStrings) {
|
TEST(ContainerNamesTest, CheckFixedStrings) {
|
||||||
|
|
Loading…
Reference in New Issue