Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(518)

Side by Side Diff: media/filters/ffmpeg_demuxer.cc

Issue 10829470: Support for parsing encrypted WebM streams by src. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed bug with playing latest encrypted WebM. Addressing comments. Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/filters/ffmpeg_demuxer.h" 5 #include "media/filters/ffmpeg_demuxer.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 9
10 #include "base/base64.h"
10 #include "base/bind.h" 11 #include "base/bind.h"
11 #include "base/callback.h" 12 #include "base/callback.h"
12 #include "base/command_line.h" 13 #include "base/command_line.h"
13 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/scoped_ptr.h"
14 #include "base/message_loop.h" 15 #include "base/message_loop.h"
15 #include "base/stl_util.h" 16 #include "base/stl_util.h"
16 #include "base/string_util.h" 17 #include "base/string_util.h"
17 #include "base/time.h" 18 #include "base/time.h"
18 #include "media/base/audio_decoder_config.h" 19 #include "media/base/audio_decoder_config.h"
19 #include "media/base/decoder_buffer.h" 20 #include "media/base/decoder_buffer.h"
20 #include "media/base/limits.h" 21 #include "media/base/limits.h"
21 #include "media/base/media_switches.h" 22 #include "media/base/media_switches.h"
22 #include "media/base/video_decoder_config.h" 23 #include "media/base/video_decoder_config.h"
24 #include "media/crypto/decryptor_helpers.h"
23 #include "media/ffmpeg/ffmpeg_common.h" 25 #include "media/ffmpeg/ffmpeg_common.h"
24 #include "media/filters/ffmpeg_glue.h" 26 #include "media/filters/ffmpeg_glue.h"
25 #include "media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.h" 27 #include "media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.h"
28 #include "media/webm/webm_crypt_helpers.h"
26 29
27 namespace media { 30 namespace media {
28 31
29 // 32 //
30 // FFmpegDemuxerStream 33 // FFmpegDemuxerStream
31 // 34 //
32 FFmpegDemuxerStream::FFmpegDemuxerStream( 35 FFmpegDemuxerStream::FFmpegDemuxerStream(
33 FFmpegDemuxer* demuxer, 36 FFmpegDemuxer* demuxer,
34 AVStream* stream) 37 AVStream* stream)
35 : demuxer_(demuxer), 38 : demuxer_(demuxer),
(...skipping 13 matching lines...) Expand all
49 type_ = VIDEO; 52 type_ = VIDEO;
50 AVStreamToVideoDecoderConfig(stream, &video_config_); 53 AVStreamToVideoDecoderConfig(stream, &video_config_);
51 break; 54 break;
52 default: 55 default:
53 NOTREACHED(); 56 NOTREACHED();
54 break; 57 break;
55 } 58 }
56 59
57 // Calculate the duration. 60 // Calculate the duration.
58 duration_ = ConvertStreamTimestamp(stream->time_base, stream->duration); 61 duration_ = ConvertStreamTimestamp(stream->time_base, stream->duration);
62
63 // *** DEBUG Until FFmpeg metadata "enck_key_id" is added for windows. ***
64 //av_dict_set(stream->metadata, "enc_key_id", "DEBUG_KEY_ID_REMOVE", 0);
65 // *** DEBUG Until FFmpeg metadata "enck_key_id" is added for windows. ***
66
67 // Only supports WebM for now.
68 AVDictionaryEntry *key = av_dict_get(stream->metadata, "enc_key_id", NULL, 0);
69 if (key) {
70 CHECK(key->value);
xhwang 2012/08/29 05:08:14 Can a malformed file generate a |key| without valu
fgalligan1 2013/03/09 01:10:59 Done.
71 base::StringPiece base64_key_id(key->value);
72 std::string enc_key_id;
73 base::Base64Decode(base64_key_id, &enc_key_id);
74 CHECK(!enc_key_id.empty());
xhwang 2012/08/29 05:08:14 Same as above, add error handling code instead of
fgalligan1 2013/03/09 01:10:59 Done.
fgalligan1 2013/03/09 01:10:59 Done.
75 demuxer_->NeedKey(enc_key_id);
76 current_key_id_.assign(enc_key_id);
77 }
59 } 78 }
60 79
61 bool FFmpegDemuxerStream::HasPendingReads() { 80 bool FFmpegDemuxerStream::HasPendingReads() {
62 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread()); 81 DCHECK(demuxer_->message_loop()->BelongsToCurrentThread());
63 base::AutoLock auto_lock(lock_); 82 base::AutoLock auto_lock(lock_);
64 DCHECK(!stopped_ || read_queue_.empty()) 83 DCHECK(!stopped_ || read_queue_.empty())
65 << "Read queue should have been emptied if demuxing stream is stopped"; 84 << "Read queue should have been emptied if demuxing stream is stopped";
66 return !read_queue_.empty(); 85 return !read_queue_.empty();
67 } 86 }
68 87
(...skipping 10 matching lines...) Expand all
79 scoped_refptr<DecoderBuffer> buffer; 98 scoped_refptr<DecoderBuffer> buffer;
80 if (!packet.get()) { 99 if (!packet.get()) {
81 buffer = DecoderBuffer::CreateEOSBuffer(); 100 buffer = DecoderBuffer::CreateEOSBuffer();
82 } else { 101 } else {
83 // Convert the packet if there is a bitstream filter. 102 // Convert the packet if there is a bitstream filter.
84 if (packet->data && bitstream_converter_.get() && 103 if (packet->data && bitstream_converter_.get() &&
85 !bitstream_converter_->ConvertPacket(packet.get())) { 104 !bitstream_converter_->ConvertPacket(packet.get())) {
86 LOG(ERROR) << "Format converstion failed."; 105 LOG(ERROR) << "Format converstion failed.";
87 } 106 }
88 107
89 // If a packet is returned by FFmpeg's av_parser_parse2() the packet will 108 // TODO (fgalligan): Remove the WebM specific code to process an encrypted
90 // reference inner memory of FFmpeg. As such we should transfer the packet 109 // buffer. Create a generalized class or function that can be called that
91 // into memory we control. 110 // will work for all encrypted formats.
92 buffer = DecoderBuffer::CopyFrom(packet->data, packet->size); 111 buffer = WebMCopyBufferCheckIfEncrypted(
112 packet->data,
113 packet->size,
114 reinterpret_cast<const uint8*>(current_key_id_.data()),
115 current_key_id_.size());
93 buffer->SetTimestamp(ConvertStreamTimestamp( 116 buffer->SetTimestamp(ConvertStreamTimestamp(
94 stream_->time_base, packet->pts)); 117 stream_->time_base, packet->pts));
95 buffer->SetDuration(ConvertStreamTimestamp( 118 buffer->SetDuration(ConvertStreamTimestamp(
96 stream_->time_base, packet->duration)); 119 stream_->time_base, packet->duration));
97 if (buffer->GetTimestamp() != kNoTimestamp() && 120 if (buffer->GetTimestamp() != kNoTimestamp() &&
98 last_packet_timestamp_ != kNoTimestamp() && 121 last_packet_timestamp_ != kNoTimestamp() &&
99 last_packet_timestamp_ < buffer->GetTimestamp()) { 122 last_packet_timestamp_ < buffer->GetTimestamp()) {
100 buffered_ranges_.Add(last_packet_timestamp_, buffer->GetTimestamp()); 123 buffered_ranges_.Add(last_packet_timestamp_, buffer->GetTimestamp());
101 demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind( 124 demuxer_->message_loop()->PostTask(FROM_HERE, base::Bind(
102 &FFmpegDemuxer::NotifyBufferingChanged, demuxer_)); 125 &FFmpegDemuxer::NotifyBufferingChanged, demuxer_));
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 return kNoTimestamp(); 273 return kNoTimestamp();
251 274
252 return ConvertFromTimeBase(time_base, timestamp); 275 return ConvertFromTimeBase(time_base, timestamp);
253 } 276 }
254 277
255 // 278 //
256 // FFmpegDemuxer 279 // FFmpegDemuxer
257 // 280 //
258 FFmpegDemuxer::FFmpegDemuxer( 281 FFmpegDemuxer::FFmpegDemuxer(
259 const scoped_refptr<base::MessageLoopProxy>& message_loop, 282 const scoped_refptr<base::MessageLoopProxy>& message_loop,
260 const scoped_refptr<DataSource>& data_source) 283 const scoped_refptr<DataSource>& data_source,
284 const FFmpegNeedKeyCB& need_key_cb)
261 : host_(NULL), 285 : host_(NULL),
262 message_loop_(message_loop), 286 message_loop_(message_loop),
263 format_context_(NULL), 287 format_context_(NULL),
264 data_source_(data_source), 288 data_source_(data_source),
265 read_event_(false, false), 289 read_event_(false, false),
266 read_has_failed_(false), 290 read_has_failed_(false),
267 last_read_bytes_(0), 291 last_read_bytes_(0),
268 read_position_(0), 292 read_position_(0),
269 bitrate_(0), 293 bitrate_(0),
270 start_time_(kNoTimestamp()), 294 start_time_(kNoTimestamp()),
271 audio_disabled_(false), 295 audio_disabled_(false),
272 duration_known_(false) { 296 duration_known_(false),
297 need_key_cb_(need_key_cb) {
273 DCHECK(message_loop_); 298 DCHECK(message_loop_);
274 DCHECK(data_source_); 299 DCHECK(data_source_);
275 } 300 }
276 301
277 FFmpegDemuxer::~FFmpegDemuxer() { 302 FFmpegDemuxer::~FFmpegDemuxer() {
278 // In this destructor, we clean up resources held by FFmpeg. It is ugly to 303 // In this destructor, we clean up resources held by FFmpeg. It is ugly to
279 // close the codec contexts here because the corresponding codecs are opened 304 // close the codec contexts here because the corresponding codecs are opened
280 // in the decoder filters. By reaching this point, all filters should have 305 // in the decoder filters. By reaching this point, all filters should have
281 // stopped, so this is the only safe place to do the global clean up. 306 // stopped, so this is the only safe place to do the global clean up.
282 // TODO(hclam): close the codecs in the corresponding decoders. 307 // TODO(hclam): close the codecs in the corresponding decoders.
(...skipping 26 matching lines...) Expand all
309 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) { 334 void FFmpegDemuxer::SetPlaybackRate(float playback_rate) {
310 DCHECK(data_source_.get()); 335 DCHECK(data_source_.get());
311 data_source_->SetPlaybackRate(playback_rate); 336 data_source_->SetPlaybackRate(playback_rate);
312 } 337 }
313 338
314 void FFmpegDemuxer::OnAudioRendererDisabled() { 339 void FFmpegDemuxer::OnAudioRendererDisabled() {
315 message_loop_->PostTask(FROM_HERE, base::Bind( 340 message_loop_->PostTask(FROM_HERE, base::Bind(
316 &FFmpegDemuxer::DisableAudioStreamTask, this)); 341 &FFmpegDemuxer::DisableAudioStreamTask, this));
317 } 342 }
318 343
344 void FFmpegDemuxer::NeedKey(const std::string& key_id) {
345 int key_id_size = key_id.size();
346 scoped_array<uint8> key_id_local(new uint8[key_id_size]);
347 memcpy(key_id_local.get(), key_id.data(), key_id_size);
348 need_key_cb_.Run(key_id_local.Pass(), key_id_size);
xhwang 2012/08/29 05:08:14 Sad to see this conversion again. I think we need
349 }
350
319 void FFmpegDemuxer::Initialize(DemuxerHost* host, 351 void FFmpegDemuxer::Initialize(DemuxerHost* host,
320 const PipelineStatusCB& status_cb) { 352 const PipelineStatusCB& status_cb) {
321 message_loop_->PostTask(FROM_HERE, base::Bind( 353 message_loop_->PostTask(FROM_HERE, base::Bind(
322 &FFmpegDemuxer::InitializeTask, this, host, status_cb)); 354 &FFmpegDemuxer::InitializeTask, this, host, status_cb));
323 } 355 }
324 356
325 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream( 357 scoped_refptr<DemuxerStream> FFmpegDemuxer::GetStream(
326 DemuxerStream::Type type) { 358 DemuxerStream::Type type) {
327 return GetFFmpegStream(type); 359 return GetFFmpegStream(type);
328 } 360 }
(...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after
727 } else if (audio) { 759 } else if (audio) {
728 buffered = audio->GetBufferedRanges(); 760 buffered = audio->GetBufferedRanges();
729 } else if (video) { 761 } else if (video) {
730 buffered = video->GetBufferedRanges(); 762 buffered = video->GetBufferedRanges();
731 } 763 }
732 for (size_t i = 0; i < buffered.size(); ++i) 764 for (size_t i = 0; i < buffered.size(); ++i)
733 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i)); 765 host_->AddBufferedTimeRange(buffered.start(i), buffered.end(i));
734 } 766 }
735 767
736 } // namespace media 768 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698