| OLD | NEW |
| 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/webm/webm_stream_parser.h" | 5 #include "media/webm/webm_stream_parser.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/callback.h" | 9 #include "base/callback.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 bool Parse(const uint8* data, int size); | 36 bool Parse(const uint8* data, int size); |
| 37 | 37 |
| 38 const AudioDecoderConfig& audio_config() const; | 38 const AudioDecoderConfig& audio_config() const; |
| 39 const VideoDecoderConfig& video_config() const; | 39 const VideoDecoderConfig& video_config() const; |
| 40 | 40 |
| 41 private: | 41 private: |
| 42 static const uint8 kWebMHeader[]; | 42 static const uint8 kWebMHeader[]; |
| 43 static const int kSegmentSizeOffset; | 43 static const int kSegmentSizeOffset; |
| 44 static const uint8 kEmptyCluster[]; | 44 static const uint8 kEmptyCluster[]; |
| 45 | 45 |
| 46 AVFormatContext* CreateFormatContext(const uint8* data, int size); | 46 bool OpenFormatContext(const uint8* data, int size); |
| 47 bool SetupStreamConfigs(); | 47 bool SetupStreamConfigs(); |
| 48 | 48 |
| 49 AudioDecoderConfig audio_config_; | 49 AudioDecoderConfig audio_config_; |
| 50 VideoDecoderConfig video_config_; | 50 VideoDecoderConfig video_config_; |
| 51 | 51 |
| 52 // Backing buffer for |url_protocol_|. | 52 // Backing buffer for |url_protocol_|. |
| 53 scoped_array<uint8> url_protocol_buffer_; | 53 scoped_array<uint8> url_protocol_buffer_; |
| 54 | 54 |
| 55 // Protocol used by |format_context_|. It must outlive the context object. | 55 // Protocol used by FFmpegGlue. It must outlive the context object. |
| 56 scoped_ptr<InMemoryUrlProtocol> url_protocol_; | 56 scoped_ptr<InMemoryUrlProtocol> url_protocol_; |
| 57 | 57 |
| 58 // FFmpeg format context for this demuxer. It is created by | 58 // Glue for interfacing InMemoryUrlProtocol with FFmpeg. |
| 59 // avformat_open_input() during demuxer initialization and cleaned up with | 59 scoped_ptr<FFmpegGlue> glue_; |
| 60 // DestroyAVFormatContext() in the destructor. | |
| 61 AVFormatContext* format_context_; | |
| 62 | 60 |
| 63 DISALLOW_COPY_AND_ASSIGN(FFmpegConfigHelper); | 61 DISALLOW_COPY_AND_ASSIGN(FFmpegConfigHelper); |
| 64 }; | 62 }; |
| 65 | 63 |
| 66 // WebM File Header. This is prepended to the INFO & TRACKS | 64 // WebM File Header. This is prepended to the INFO & TRACKS |
| 67 // data passed to Init() before handing it to FFmpeg. Essentially | 65 // data passed to Init() before handing it to FFmpeg. Essentially |
| 68 // we are making the INFO & TRACKS data look like a small WebM | 66 // we are making the INFO & TRACKS data look like a small WebM |
| 69 // file so we can use FFmpeg to initialize the AVFormatContext. | 67 // file so we can use FFmpeg to initialize the AVFormatContext. |
| 70 const uint8 FFmpegConfigHelper::kWebMHeader[] = { | 68 const uint8 FFmpegConfigHelper::kWebMHeader[] = { |
| 71 0x1A, 0x45, 0xDF, 0xA3, 0x9F, // EBML (size = 0x1f) | 69 0x1A, 0x45, 0xDF, 0xA3, 0x9F, // EBML (size = 0x1f) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 83 }; | 81 }; |
| 84 | 82 |
| 85 // Offset of the segment size field in kWebMHeader. Used to update | 83 // Offset of the segment size field in kWebMHeader. Used to update |
| 86 // the segment size field before handing the buffer to FFmpeg. | 84 // the segment size field before handing the buffer to FFmpeg. |
| 87 const int FFmpegConfigHelper::kSegmentSizeOffset = sizeof(kWebMHeader) - 8; | 85 const int FFmpegConfigHelper::kSegmentSizeOffset = sizeof(kWebMHeader) - 8; |
| 88 | 86 |
| 89 const uint8 FFmpegConfigHelper::kEmptyCluster[] = { | 87 const uint8 FFmpegConfigHelper::kEmptyCluster[] = { |
| 90 0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0) | 88 0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0) |
| 91 }; | 89 }; |
| 92 | 90 |
| 93 FFmpegConfigHelper::FFmpegConfigHelper() : format_context_(NULL) {} | 91 FFmpegConfigHelper::FFmpegConfigHelper() {} |
| 94 | 92 |
| 95 FFmpegConfigHelper::~FFmpegConfigHelper() { | 93 FFmpegConfigHelper::~FFmpegConfigHelper() { |
| 96 if (!format_context_) | |
| 97 return; | |
| 98 | |
| 99 DestroyAVFormatContext(format_context_); | |
| 100 format_context_ = NULL; | |
| 101 | |
| 102 if (url_protocol_.get()) { | 94 if (url_protocol_.get()) { |
| 103 FFmpegGlue::GetInstance()->RemoveProtocol(url_protocol_.get()); | |
| 104 url_protocol_.reset(); | 95 url_protocol_.reset(); |
| 105 url_protocol_buffer_.reset(); | 96 url_protocol_buffer_.reset(); |
| 106 } | 97 } |
| 98 |
| 99 if (glue_.get()) |
| 100 glue_.reset(); |
| 107 } | 101 } |
| 108 | 102 |
| 109 bool FFmpegConfigHelper::Parse(const uint8* data, int size) { | 103 bool FFmpegConfigHelper::Parse(const uint8* data, int size) { |
| 110 format_context_ = CreateFormatContext(data, size); | 104 return OpenFormatContext(data, size) && SetupStreamConfigs(); |
| 111 return format_context_ && SetupStreamConfigs(); | |
| 112 } | 105 } |
| 113 | 106 |
| 114 const AudioDecoderConfig& FFmpegConfigHelper::audio_config() const { | 107 const AudioDecoderConfig& FFmpegConfigHelper::audio_config() const { |
| 115 return audio_config_; | 108 return audio_config_; |
| 116 } | 109 } |
| 117 | 110 |
| 118 const VideoDecoderConfig& FFmpegConfigHelper::video_config() const { | 111 const VideoDecoderConfig& FFmpegConfigHelper::video_config() const { |
| 119 return video_config_; | 112 return video_config_; |
| 120 } | 113 } |
| 121 | 114 |
| 122 AVFormatContext* FFmpegConfigHelper::CreateFormatContext(const uint8* data, | 115 bool FFmpegConfigHelper::OpenFormatContext(const uint8* data, int size) { |
| 123 int size) { | |
| 124 DCHECK(!url_protocol_.get()); | 116 DCHECK(!url_protocol_.get()); |
| 125 DCHECK(!url_protocol_buffer_.get()); | 117 DCHECK(!url_protocol_buffer_.get()); |
| 118 DCHECK(!glue_.get()); |
| 126 | 119 |
| 127 int segment_size = size + sizeof(kEmptyCluster); | 120 int segment_size = size + sizeof(kEmptyCluster); |
| 128 int buf_size = sizeof(kWebMHeader) + segment_size; | 121 int buf_size = sizeof(kWebMHeader) + segment_size; |
| 129 url_protocol_buffer_.reset(new uint8[buf_size]); | 122 url_protocol_buffer_.reset(new uint8[buf_size]); |
| 130 uint8* buf = url_protocol_buffer_.get(); | 123 uint8* buf = url_protocol_buffer_.get(); |
| 131 memcpy(buf, kWebMHeader, sizeof(kWebMHeader)); | 124 memcpy(buf, kWebMHeader, sizeof(kWebMHeader)); |
| 132 memcpy(buf + sizeof(kWebMHeader), data, size); | 125 memcpy(buf + sizeof(kWebMHeader), data, size); |
| 133 memcpy(buf + sizeof(kWebMHeader) + size, kEmptyCluster, | 126 memcpy(buf + sizeof(kWebMHeader) + size, kEmptyCluster, |
| 134 sizeof(kEmptyCluster)); | 127 sizeof(kEmptyCluster)); |
| 135 | 128 |
| 136 // Update the segment size in the buffer. | 129 // Update the segment size in the buffer. |
| 137 int64 tmp = (segment_size & GG_LONGLONG(0x00FFFFFFFFFFFFFF)) | | 130 int64 tmp = (segment_size & GG_LONGLONG(0x00FFFFFFFFFFFFFF)) | |
| 138 GG_LONGLONG(0x0100000000000000); | 131 GG_LONGLONG(0x0100000000000000); |
| 139 for (int i = 0; i < 8; i++) { | 132 for (int i = 0; i < 8; i++) { |
| 140 buf[kSegmentSizeOffset + i] = (tmp >> (8 * (7 - i))) & 0xff; | 133 buf[kSegmentSizeOffset + i] = (tmp >> (8 * (7 - i))) & 0xff; |
| 141 } | 134 } |
| 142 | 135 |
| 143 url_protocol_.reset(new InMemoryUrlProtocol(buf, buf_size, true)); | 136 url_protocol_.reset(new InMemoryUrlProtocol(buf, buf_size, true)); |
| 144 std::string key = FFmpegGlue::GetInstance()->AddProtocol(url_protocol_.get()); | 137 glue_.reset(new FFmpegGlue(url_protocol_.get())); |
| 145 | 138 |
| 146 // Open FFmpeg AVFormatContext. | 139 // Open FFmpeg AVFormatContext. |
| 147 AVFormatContext* context = NULL; | 140 return glue_->OpenContext(); |
| 148 int result = avformat_open_input(&context, key.c_str(), NULL, NULL); | |
| 149 | |
| 150 if (result < 0) | |
| 151 return NULL; | |
| 152 | |
| 153 return context; | |
| 154 } | 141 } |
| 155 | 142 |
| 156 bool FFmpegConfigHelper::SetupStreamConfigs() { | 143 bool FFmpegConfigHelper::SetupStreamConfigs() { |
| 157 int result = avformat_find_stream_info(format_context_, NULL); | 144 AVFormatContext* format_context = glue_->format_context(); |
| 145 int result = avformat_find_stream_info(format_context, NULL); |
| 158 | 146 |
| 159 if (result < 0) | 147 if (result < 0) |
| 160 return false; | 148 return false; |
| 161 | 149 |
| 162 bool no_supported_streams = true; | 150 bool no_supported_streams = true; |
| 163 for (size_t i = 0; i < format_context_->nb_streams; ++i) { | 151 for (size_t i = 0; i < format_context->nb_streams; ++i) { |
| 164 AVStream* stream = format_context_->streams[i]; | 152 AVStream* stream = format_context->streams[i]; |
| 165 AVCodecContext* codec_context = stream->codec; | 153 AVCodecContext* codec_context = stream->codec; |
| 166 AVMediaType codec_type = codec_context->codec_type; | 154 AVMediaType codec_type = codec_context->codec_type; |
| 167 | 155 |
| 168 if (codec_type == AVMEDIA_TYPE_AUDIO && | 156 if (codec_type == AVMEDIA_TYPE_AUDIO && |
| 169 stream->codec->codec_id == CODEC_ID_VORBIS && | 157 stream->codec->codec_id == CODEC_ID_VORBIS && |
| 170 !audio_config_.IsValidConfig()) { | 158 !audio_config_.IsValidConfig()) { |
| 171 AVCodecContextToAudioDecoderConfig(stream->codec, &audio_config_); | 159 AVCodecContextToAudioDecoderConfig(stream->codec, &audio_config_); |
| 172 no_supported_streams = false; | 160 no_supported_streams = false; |
| 173 continue; | 161 continue; |
| 174 } | 162 } |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 | 462 |
| 475 void WebMStreamParser::FireNeedKey(const std::string& key_id) { | 463 void WebMStreamParser::FireNeedKey(const std::string& key_id) { |
| 476 int key_id_size = key_id.size(); | 464 int key_id_size = key_id.size(); |
| 477 DCHECK_GT(key_id_size, 0); | 465 DCHECK_GT(key_id_size, 0); |
| 478 scoped_array<uint8> key_id_array(new uint8[key_id_size]); | 466 scoped_array<uint8> key_id_array(new uint8[key_id_size]); |
| 479 memcpy(key_id_array.get(), key_id.data(), key_id_size); | 467 memcpy(key_id_array.get(), key_id.data(), key_id_size); |
| 480 need_key_cb_.Run(kWebMInitDataType, key_id_array.Pass(), key_id_size); | 468 need_key_cb_.Run(kWebMInitDataType, key_id_array.Pass(), key_id_size); |
| 481 } | 469 } |
| 482 | 470 |
| 483 } // namespace media | 471 } // namespace media |
| OLD | NEW |