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:
Jacob Trimble 2015-12-16 10:20:13 -08:00
parent af7d6a7921
commit 05f5682728
6 changed files with 114 additions and 21 deletions

View File

@ -19,7 +19,6 @@
#include "packager/base/logging.h"
#include "packager/base/stl_util.h"
#include "packager/base/strings/string_split.h"
#include "packager/base/strings/string_util.h"
#include "packager/base/strings/stringprintf.h"
#include "packager/base/threading/simple_thread.h"
#include "packager/base/time/clock.h"
@ -67,7 +66,10 @@ const char kUsage[] =
"If not specified, its value may be estimated.\n"
" - language (lang): Optional value which contains a user-specified "
"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";
@ -183,22 +185,13 @@ bool StreamInfoToTextMediaInfo(const StreamDescriptor& stream_descriptor,
return true;
}
scoped_ptr<Muxer> CreateOutputMuxer(const MuxerOptions& options) {
// TODO(modmaker): Add a config option for output format
const std::string& file_name = options.output_file_name;
if (base::EndsWith(file_name, ".webm",
base::CompareCase::INSENSITIVE_ASCII)) {
scoped_ptr<Muxer> CreateOutputMuxer(const MuxerOptions& options,
MediaContainerName container) {
if (container == CONTAINER_WEBM) {
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 {
LOG(ERROR) << "Unrecognized output format " << file_name;
return NULL;
DCHECK_EQ(container, CONTAINER_MOV);
return scoped_ptr<Muxer>(new mp4::MP4Muxer(options));
}
}
@ -282,9 +275,20 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
}
DCHECK(!remux_jobs->empty());
scoped_ptr<Muxer> muxer(CreateOutputMuxer(stream_muxer_options));
if (!muxer)
return false;
MediaContainerName output_format = stream_iter->output_format;
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;
}
}
scoped_ptr<Muxer> muxer(
CreateOutputMuxer(stream_muxer_options, output_format));
if (FLAGS_use_fake_clock_for_muxer) muxer->set_clock(fake_clock);
if (key_source) {

View File

@ -25,6 +25,7 @@ enum FieldType {
kSegmentTemplateField,
kBandwidthField,
kLanguageField,
kOutputFormatField,
};
struct FieldNameToTypeMapping {
@ -47,6 +48,8 @@ const FieldNameToTypeMapping kFieldNameTypeMappings[] = {
{ "bitrate", kBandwidthField },
{ "language", kLanguageField },
{ "lang", kLanguageField },
{ "output_format", kOutputFormatField },
{ "format", kOutputFormatField },
};
FieldType GetFieldType(const std::string& field_name) {
@ -59,7 +62,8 @@ FieldType GetFieldType(const std::string& field_name) {
} // anonymous namespace
StreamDescriptor::StreamDescriptor() : bandwidth(0) {}
StreamDescriptor::StreamDescriptor()
: bandwidth(0), output_format(CONTAINER_UNKNOWN) {}
StreamDescriptor::~StreamDescriptor() {}
@ -110,6 +114,16 @@ bool InsertStreamDescriptor(const std::string& descriptor_string,
descriptor.language = language;
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:
LOG(ERROR) << "Unknown field in stream descriptor (\"" << iter->first
<< "\").";

View File

@ -12,6 +12,8 @@
#include <set>
#include <string>
#include "media/base/container_names.h"
namespace edash_packager {
namespace media {
@ -27,6 +29,7 @@ struct StreamDescriptor {
std::string segment_template;
uint32_t bandwidth;
std::string language;
MediaContainerName output_format;
};
class StreamDescriptorCompareFn {

View File

@ -12,6 +12,7 @@
#include <limits>
#include "packager/base/logging.h"
#include "packager/base/strings/string_util.h"
#include "packager/media/base/bit_reader.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;
}
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 edash_packager

View File

@ -7,6 +7,8 @@
#include <stdint.h>
#include <string>
namespace edash_packager {
namespace media {
@ -56,9 +58,18 @@ enum MediaContainerName {
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);
/// 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 edash_packager

View File

@ -83,6 +83,35 @@ uint8_t kBug263073Buffer[] = {
0x67, 0x64, 0x00, 0x28, 0xac, 0x2c, 0xa4, 0x01, 0xe0, 0x08, 0x9f,
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.
// This is to verify that the TAG matches the first 4 characters of the string.
TEST(ContainerNamesTest, CheckFixedStrings) {