Skip to content

Commit

Permalink
[media] Support progressive playback
Browse files Browse the repository at this point in the history
This PR brings the progressive demuxer from Cobalt C25 to support progressive videos.

b/322033277
  • Loading branch information
borongc committed Nov 22, 2024
1 parent f245d4e commit daea30c
Show file tree
Hide file tree
Showing 27 changed files with 908 additions and 821 deletions.
1 change: 1 addition & 0 deletions media/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ test("media_unittests") {
# TODO(cobalt, b/379934658): add starboard_renderer_test.
# TODO(cobalt, b/379936173): enable starboard_utils_test.
# TODO(cobalt, b/379934533): enable bidirectional_fit_reuse_allocator_test.
# TODO(cobalt, b/380335617): enable progressive demuxer tests.
# deps += ["//media/starboard:unit_tests"]
}

Expand Down
1 change: 1 addition & 0 deletions media/base/decoder_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ class MEDIA_EXPORT DecoderBuffer
// If there's no data in this buffer, it represents end of stream.
#if BUILDFLAG(USE_STARBOARD_MEDIA)
bool end_of_stream() const { return !data_; }
void shrink_to(size_t size) { DCHECK_LE(size, size_); size_ = size; }
#else // BUILDFLAG(USE_STARBOARD_MEDIA)
bool end_of_stream() const {
return !read_only_mapping_.IsValid() && !writable_mapping_.IsValid() &&
Expand Down
30 changes: 30 additions & 0 deletions media/filters/demuxer_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
#include "media/filters/manifest_demuxer.h"
#endif // BUILDFLAG(ENABLE_HLS_DEMUXER)

#if BUILDFLAG(ENABLE_FFMPEG)
// ProgressDemuxer is enabled when is_cobalt=true and media_use_ffmpeg=false.
#elif BUILDFLAG(IS_COBALT)
#include "media/starboard/progressive/demuxer_extension_wrapper.h"
#include "media/starboard/progressive/progressive_demuxer.h"
#endif // BUILDFLAG(IS_COBALT)

namespace media {

namespace {
Expand Down Expand Up @@ -409,6 +416,8 @@ PipelineStatus DemuxerManager::CreateDemuxer(
} else if (!load_media_source) {
#if BUILDFLAG(ENABLE_FFMPEG)
SetDemuxer(CreateFFmpegDemuxer());
#elif BUILDFLAG(IS_COBALT)
SetDemuxer(CreateProgressiveDemuxer());
#else
return DEMUXER_ERROR_COULD_NOT_OPEN;
#endif
Expand Down Expand Up @@ -576,6 +585,27 @@ std::unique_ptr<Demuxer> DemuxerManager::CreateFFmpegDemuxer() {
weak_factory_.GetWeakPtr())),
media_log_.get(), IsLocalFile(loaded_url_));
}
#elif BUILDFLAG(IS_COBALT)
std::unique_ptr<Demuxer> DemuxerManager::CreateDemuxerExtensionWrapper() {
DCHECK(data_source_);
return DemuxerExtensionWrapper::Create(
data_source_.get(), media_task_runner_);
}
std::unique_ptr<Demuxer> DemuxerManager::CreateProgressiveDemuxer() {
DCHECK(data_source_);
std::unique_ptr<Demuxer> progressive_demuxer_ = CreateDemuxerExtensionWrapper();
if (progressive_demuxer_) {
LOG(INFO) << "Using DemuxerExtensionWrapper.";
return progressive_demuxer_;
} else {
// Either the demuxer Cobalt extension was not provided, or it failed to
// create a demuxer; fall back to the ProgressiveDemuxer.
LOG(INFO) << "Using ProgressiveDemuxer.";
return std::make_unique<ProgressiveDemuxer>(
media_task_runner_, data_source_.get(),
media_log_.get());
}
}
#endif // BUILDFLAG(ENABLE_FFMPEG)

#if BUILDFLAG(ENABLE_HLS_DEMUXER)
Expand Down
3 changes: 3 additions & 0 deletions media/filters/demuxer_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ class MEDIA_EXPORT DemuxerManager {

#if BUILDFLAG(ENABLE_FFMPEG)
std::unique_ptr<media::Demuxer> CreateFFmpegDemuxer();
#elif BUILDFLAG(IS_COBALT)
std::unique_ptr<media::Demuxer> CreateDemuxerExtensionWrapper();
std::unique_ptr<media::Demuxer> CreateProgressiveDemuxer();
#endif // BUILDFLAG(ENABLE_FFMPEG)

#if BUILDFLAG(ENABLE_HLS_DEMUXER)
Expand Down
35 changes: 35 additions & 0 deletions media/starboard/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

assert(is_cobalt, "This file builds for cobalt builds, not Chromium builds")

import("//media/media_options.gni")
import("//starboard/build/buildflags.gni")

source_set("starboard") {
Expand Down Expand Up @@ -55,6 +56,28 @@ source_set("starboard") {
]

sources = []
if (!media_use_ffmpeg) {
sources += [
"progressive/avc_access_unit.cc",
"progressive/avc_access_unit.h",
"progressive/avc_parser.cc",
"progressive/avc_parser.h",
"progressive/data_source_reader.cc",
"progressive/data_source_reader.h",
"progressive/demuxer_extension_wrapper.cc",
"progressive/demuxer_extension_wrapper.h",
"progressive/mp4_map.cc",
"progressive/mp4_map.h",
"progressive/mp4_parser.cc",
"progressive/mp4_parser.h",
"progressive/progressive_demuxer.cc",
"progressive/progressive_demuxer.h",
"progressive/progressive_parser.cc",
"progressive/progressive_parser.h",
"progressive/rbsp_stream.cc",
"progressive/rbsp_stream.h",
]
}

if (use_starboard_media) {
sources += [
Expand Down Expand Up @@ -91,12 +114,24 @@ source_set("starboard") {
"//starboard/common",
]

if (!media_use_ffmpeg) {
deps += [ "//third_party/abseil-cpp:absl" ]
}

configs += [ "//media:subcomponent_config" ]
}

source_set("unit_tests") {
testonly = true
sources = []
if (!media_use_ffmpeg) {
sources += [
"progressive/demuxer_extension_wrapper_test.cc",
"progressive/mock_data_source_reader.h",
"progressive/mp4_map_unittest.cc",
"progressive/rbsp_stream_unittest.cc",
]
}
if (use_starboard_media) {
sources += [
"bidirectional_fit_reuse_allocator_test.cc",
Expand Down
104 changes: 66 additions & 38 deletions media/starboard/progressive/avc_access_unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include "cobalt/media/progressive/avc_access_unit.h"
#include "media/starboard/progressive/avc_access_unit.h"

#include <algorithm>

#include "cobalt/media/base/endian_util.h"
#include "cobalt/media/progressive/progressive_parser.h"
#include "media/base/decoder_buffer.h"
#include "media/base/timestamp_constants.h"
#include "media/starboard/progressive/endian_util.h"
#include "media/starboard/progressive/progressive_parser.h"

namespace cobalt {
namespace media {

namespace {

using ::media::DecoderBuffer;
using ::media::DemuxerStream;

bool ReadBytes(uint64 offset, size_t size, uint8* buffer,
bool ReadBytes(uint64_t offset,
size_t size,
uint8_t* buffer,
DataSourceReader* reader) {
if (reader->BlockingRead(offset, size, buffer) != size) {
LOG(ERROR) << "unable to download AU";
Expand All @@ -43,9 +41,7 @@ bool ReadBytes(uint64 offset, size_t size, uint8* buffer,
class EndOfStreamAU : public AvcAccessUnit {
public:
EndOfStreamAU(Type type, TimeDelta timestamp)
: type_(type),
timestamp_(timestamp),
duration_(::media::kInfiniteDuration) {}
: type_(type), timestamp_(timestamp), duration_(kInfiniteDuration) {}

private:
bool IsEndOfStream() const override { return true; }
Expand Down Expand Up @@ -79,13 +75,18 @@ class EndOfStreamAU : public AvcAccessUnit {

class AudioAU : public AvcAccessUnit {
public:
AudioAU(uint64 offset, size_t size, size_t prepend_size, bool is_keyframe,
TimeDelta timestamp, TimeDelta duration, ProgressiveParser* parser);
AudioAU(uint64_t offset,
size_t size,
size_t prepend_size,
bool is_keyframe,
TimeDelta timestamp,
TimeDelta duration,
ProgressiveParser* parser);

private:
bool IsEndOfStream() const override { return false; }
bool IsValid() const override {
return offset_ != 0 && size_ != 0 && timestamp_ != ::media::kNoTimestamp;
return offset_ != 0 && size_ != 0 && timestamp_ != kNoTimestamp;
}
bool Read(DataSourceReader* reader, DecoderBuffer* buffer) override;
Type GetType() const override { return DemuxerStream::AUDIO; }
Expand All @@ -98,7 +99,7 @@ class AudioAU : public AvcAccessUnit {
void SetDuration(TimeDelta duration) override { duration_ = duration; }
void SetTimestamp(TimeDelta timestamp) override { timestamp_ = timestamp; }

uint64 offset_;
uint64_t offset_;
size_t size_;
size_t prepend_size_;
bool is_keyframe_;
Expand All @@ -107,8 +108,12 @@ class AudioAU : public AvcAccessUnit {
ProgressiveParser* parser_;
};

AudioAU::AudioAU(uint64 offset, size_t size, size_t prepend_size,
bool is_keyframe, TimeDelta timestamp, TimeDelta duration,
AudioAU::AudioAU(uint64_t offset,
size_t size,
size_t prepend_size,
bool is_keyframe,
TimeDelta timestamp,
TimeDelta duration,
ProgressiveParser* parser)
: offset_(offset),
size_(size),
Expand All @@ -121,8 +126,9 @@ AudioAU::AudioAU(uint64 offset, size_t size, size_t prepend_size,
bool AudioAU::Read(DataSourceReader* reader, DecoderBuffer* buffer) {
DCHECK_LE(size_ + prepend_size_, buffer->data_size());
if (!ReadBytes(offset_, size_, buffer->writable_data() + prepend_size_,
reader))
reader)) {
return false;
}

if (!parser_->Prepend(this, buffer)) {
LOG(ERROR) << "prepend fail";
Expand All @@ -136,14 +142,19 @@ bool AudioAU::Read(DataSourceReader* reader, DecoderBuffer* buffer) {

class VideoAU : public AvcAccessUnit {
public:
VideoAU(uint64 offset, size_t size, size_t prepend_size,
uint8 length_of_nalu_size, bool is_keyframe, TimeDelta timestamp,
TimeDelta duration, ProgressiveParser* parser);
VideoAU(uint64_t offset,
size_t size,
size_t prepend_size,
uint8_t length_of_nalu_size,
bool is_keyframe,
TimeDelta timestamp,
TimeDelta duration,
ProgressiveParser* parser);

private:
bool IsEndOfStream() const override { return false; }
bool IsValid() const override {
return offset_ != 0 && size_ != 0 && timestamp_ != ::media::kNoTimestamp;
return offset_ != 0 && size_ != 0 && timestamp_ != kNoTimestamp;
}
bool Read(DataSourceReader* reader, DecoderBuffer* buffer) override;
Type GetType() const override { return DemuxerStream::VIDEO; }
Expand All @@ -160,19 +171,23 @@ class VideoAU : public AvcAccessUnit {
void SetDuration(TimeDelta duration) override { duration_ = duration; }
void SetTimestamp(TimeDelta timestamp) override { timestamp_ = timestamp; }

uint64 offset_;
uint64_t offset_;
size_t size_;
size_t prepend_size_;
uint8 length_of_nalu_size_;
uint8_t length_of_nalu_size_;
bool is_keyframe_;
TimeDelta timestamp_;
TimeDelta duration_;
ProgressiveParser* parser_;
};

VideoAU::VideoAU(uint64 offset, size_t size, size_t prepend_size,
uint8 length_of_nalu_size, bool is_keyframe,
TimeDelta timestamp, TimeDelta duration,
VideoAU::VideoAU(uint64_t offset,
size_t size,
size_t prepend_size,
uint8_t length_of_nalu_size,
bool is_keyframe,
TimeDelta timestamp,
TimeDelta duration,
ProgressiveParser* parser)
: offset_(offset),
size_(size),
Expand All @@ -188,7 +203,7 @@ VideoAU::VideoAU(uint64 offset, size_t size, size_t prepend_size,

bool VideoAU::Read(DataSourceReader* reader, DecoderBuffer* buffer) {
size_t au_left = size_; // bytes left in the AU
uint64 au_offset = offset_; // offset to read in the reader
uint64_t au_offset = offset_; // offset to read in the reader
size_t buf_left = buffer->data_size(); // bytes left in the buffer
// The current write position in the buffer
int64_t decoder_buffer_offset = prepend_size_;
Expand All @@ -197,8 +212,8 @@ bool VideoAU::Read(DataSourceReader* reader, DecoderBuffer* buffer) {
// transform it into [start code][data][start code][data]....
// The length of size is indicated by length_of_nalu_size_
while (au_left >= length_of_nalu_size_ && buf_left >= kAnnexBStartCodeSize) {
uint8 size_buf[4];
uint32 nal_size;
uint8_t size_buf[4];
uint32_t nal_size;

// Store [start code]
memcpy(buffer->writable_data() + decoder_buffer_offset, kAnnexBStartCode,
Expand All @@ -207,8 +222,9 @@ bool VideoAU::Read(DataSourceReader* reader, DecoderBuffer* buffer) {
buf_left -= kAnnexBStartCodeSize;

// Read [size]
if (!ReadBytes(au_offset, length_of_nalu_size_, size_buf, reader))
if (!ReadBytes(au_offset, length_of_nalu_size_, size_buf, reader)) {
return false;
}

au_offset += length_of_nalu_size_;
au_left -= length_of_nalu_size_;
Expand All @@ -222,7 +238,9 @@ bool VideoAU::Read(DataSourceReader* reader, DecoderBuffer* buffer) {
nal_size = endian_util::load_uint32_big_endian(size_buf);
}

if (au_left < nal_size || buf_left < nal_size) break;
if (au_left < nal_size || buf_left < nal_size) {
break;
}

// Read the [data] from reader into buf
if (!ReadBytes(au_offset, nal_size,
Expand Down Expand Up @@ -263,26 +281,36 @@ AvcAccessUnit::~AvcAccessUnit() {}

// static
scoped_refptr<AvcAccessUnit> AvcAccessUnit::CreateEndOfStreamAU(
DemuxerStream::Type type, TimeDelta timestamp) {
DemuxerStream::Type type,
TimeDelta timestamp) {
return new EndOfStreamAU(type, timestamp);
}

// static
scoped_refptr<AvcAccessUnit> AvcAccessUnit::CreateAudioAU(
uint64 offset, size_t size, size_t prepend_size, bool is_keyframe,
TimeDelta timestamp, TimeDelta duration, ProgressiveParser* parser) {
uint64_t offset,
size_t size,
size_t prepend_size,
bool is_keyframe,
TimeDelta timestamp,
TimeDelta duration,
ProgressiveParser* parser) {
return new AudioAU(offset, size, prepend_size, is_keyframe, timestamp,
duration, parser);
}

// static
scoped_refptr<AvcAccessUnit> AvcAccessUnit::CreateVideoAU(
uint64 offset, size_t size, size_t prepend_size, uint8 length_of_nalu_size,
bool is_keyframe, TimeDelta timestamp, TimeDelta duration,
uint64_t offset,
size_t size,
size_t prepend_size,
uint8_t length_of_nalu_size,
bool is_keyframe,
TimeDelta timestamp,
TimeDelta duration,
ProgressiveParser* parser) {
return new VideoAU(offset, size, prepend_size, length_of_nalu_size,
is_keyframe, timestamp, duration, parser);
}

} // namespace media
} // namespace cobalt
Loading

0 comments on commit daea30c

Please sign in to comment.