Index: media/filters/ffmpeg_text_decoder.cc |
diff --git a/media/filters/ffmpeg_text_decoder.cc b/media/filters/ffmpeg_text_decoder.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..370abdf322f8fb30a12594101f8afe4af54cffa6 |
--- /dev/null |
+++ b/media/filters/ffmpeg_text_decoder.cc |
@@ -0,0 +1,126 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "media/filters/ffmpeg_text_decoder.h" |
+ |
+#include "base/callback_helpers.h" |
+#include "media/base/bind_to_loop.h" |
+#include "media/base/decoder_buffer.h" |
+#include "media/base/demuxer.h" |
+#include "media/base/text_buffer.h" |
+#include "media/filters/ffmpeg_glue.h" |
+ |
+namespace media { |
+ |
+FFmpegTextDecoder::FFmpegTextDecoder( |
+ const scoped_refptr<base::MessageLoopProxy>& message_loop) |
+ : message_loop_(message_loop), |
+ weak_factory_(this) { |
+} |
+ |
+FFmpegTextDecoder::~FFmpegTextDecoder() { |
+} |
+ |
+void FFmpegTextDecoder::Initialize(Demuxer* demuxer) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ DCHECK_NE(demuxer, static_cast<Demuxer*>(NULL)); |
+ |
+ FFmpegGlue::InitializeFFmpeg(); |
+ |
+ if (!demuxer_streams_.empty()) { |
+ // TODO(scherkus): initialization currently happens more than once in |
+ // PipelineIntegrationTest.BasicPlayback. |
acolwell GONE FROM CHROMIUM
2013/09/12 00:15:15
Do we really need this? I don't think we should be
Matthew Heaney (Chromium)
2013/09/13 19:51:54
Done.
|
+ LOG(ERROR) << "Initialize has already been called."; |
+ CHECK(false); |
+ } |
+ |
+ weak_this_ = weak_factory_.GetWeakPtr(); |
+ |
+ int stream_count = demuxer->GetStreamCount(); |
+ demuxer_streams_.reserve(stream_count); |
+ |
+ for (int idx = 0; idx < stream_count; ++idx) { |
+ DemuxerStream* stream = demuxer->GetStreamByIndex(idx); |
+ if (stream == NULL || stream->type() != DemuxerStream::TEXT) { |
+ demuxer_streams_.push_back(NULL); |
+ } else { |
+ demuxer_streams_.push_back(stream); |
+ } |
+ } |
+ |
+ read_callbacks_.resize(stream_count); |
+} |
+ |
+void FFmpegTextDecoder::Read(int index, const ReadCB& read_cb) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ DCHECK(!read_cb.is_null()); |
+ |
+ ReadCB& cb = read_callbacks_[index]; |
+ CHECK(cb.is_null()) << "Overlapping decodes are not supported."; |
+ |
+ cb = BindToCurrentLoop(read_cb); |
+ |
+ DemuxerStream* stream = demuxer_streams_[index]; |
+ CHECK(stream); |
+ |
+ stream->Read(base::Bind( |
+ &FFmpegTextDecoder::BufferReady, weak_this_, index)); |
+} |
+ |
+void FFmpegTextDecoder::BufferReady( |
acolwell GONE FROM CHROMIUM
2013/09/12 00:15:15
nit:There doesn't appear to be anything FFmpeg spe
Matthew Heaney (Chromium)
2013/09/13 19:51:54
Done.
|
+ int index, |
+ DemuxerStream::Status status, |
+ const scoped_refptr<DecoderBuffer>& input) { |
+ DCHECK(message_loop_->BelongsToCurrentThread()); |
+ |
+ ReadCB& read_cb = read_callbacks_[index]; |
+ DCHECK(!read_cb.is_null()); |
+ |
+ if (status == DemuxerStream::kAborted) { |
+ DCHECK(!input.get()); |
+ base::ResetAndReturn(&read_cb).Run(index, NULL); |
+ return; |
+ } |
+ |
+ if (input->end_of_stream()) { |
+ base::ResetAndReturn(&read_cb).Run(index, NULL); |
+ return; |
+ } |
+ |
+ DCHECK_EQ(status, DemuxerStream::kOk); |
+ DCHECK(input.get()); |
+ |
+ scoped_refptr<TextBuffer> text_buffer( |
+ new TextBuffer(input->timestamp(), |
+ input->duration())); |
+ |
+ // The side data here contains both the cue id and cue settings, |
+ // separated using a 0xFF marker. |
+ const uint8* side_data = input->side_data(); |
+ DCHECK_NE(side_data, static_cast<const uint8*>(NULL)); |
+ |
+ int side_data_size = input->side_data_size(); |
+ DCHECK_GE(side_data_size, 1); |
+ |
+ const uint8* side_data_end = side_data + side_data_size; |
+ |
+ const uint8* id_end = std::find(side_data, side_data_end, 0xFF); |
+ DCHECK_NE(id_end, side_data_end); |
+ DCHECK_EQ(*id_end, 0xFF); |
+ |
+ int id_size = id_end - side_data; |
+ DCHECK_GE(id_size, 0); |
+ |
+ text_buffer->set_id(side_data, id_size); |
+ |
+ int settings_size = side_data_size - id_size - 1; |
+ DCHECK_GE(settings_size, 0); |
+ |
+ text_buffer->set_settings(id_end + 1, settings_size); |
+ text_buffer->set_text(input->data(), input->data_size()); |
+ |
+ base::ResetAndReturn(&read_cb).Run(index, text_buffer); |
+} |
+ |
+} // namespace media |