| 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 22 matching lines...) Expand all Loading... |
| 33 bool Parse(const uint8* data, int size); | 33 bool Parse(const uint8* data, int size); |
| 34 | 34 |
| 35 const AudioDecoderConfig& audio_config() const; | 35 const AudioDecoderConfig& audio_config() const; |
| 36 const VideoDecoderConfig& video_config() const; | 36 const VideoDecoderConfig& video_config() const; |
| 37 | 37 |
| 38 private: | 38 private: |
| 39 static const uint8 kWebMHeader[]; | 39 static const uint8 kWebMHeader[]; |
| 40 static const int kSegmentSizeOffset; | 40 static const int kSegmentSizeOffset; |
| 41 static const uint8 kEmptyCluster[]; | 41 static const uint8 kEmptyCluster[]; |
| 42 | 42 |
| 43 AVFormatContext* CreateFormatContext(const uint8* data, int size); | 43 bool OpenFormatContext(const uint8* data, int size); |
| 44 bool SetupStreamConfigs(); | 44 bool SetupStreamConfigs(); |
| 45 | 45 |
| 46 AudioDecoderConfig audio_config_; | 46 AudioDecoderConfig audio_config_; |
| 47 VideoDecoderConfig video_config_; | 47 VideoDecoderConfig video_config_; |
| 48 | 48 |
| 49 // Backing buffer for |url_protocol_|. | 49 // Backing buffer for |url_protocol_|. |
| 50 scoped_array<uint8> url_protocol_buffer_; | 50 scoped_array<uint8> url_protocol_buffer_; |
| 51 | 51 |
| 52 // Protocol used by |format_context_|. It must outlive the context object. | 52 // Protocol used by FFmpegGlue. It must outlive the context object. |
| 53 scoped_ptr<InMemoryUrlProtocol> url_protocol_; | 53 scoped_ptr<InMemoryUrlProtocol> url_protocol_; |
| 54 | 54 |
| 55 // FFmpeg format context for this demuxer. It is created by | 55 // Glue for interfacing InMemoryUrlProtocol with FFmpeg. |
| 56 // avformat_open_input() during demuxer initialization and cleaned up with | 56 scoped_ptr<FFmpegGlue> glue_; |
| 57 // DestroyAVFormatContext() in the destructor. | |
| 58 AVFormatContext* format_context_; | |
| 59 | 57 |
| 60 DISALLOW_COPY_AND_ASSIGN(FFmpegConfigHelper); | 58 DISALLOW_COPY_AND_ASSIGN(FFmpegConfigHelper); |
| 61 }; | 59 }; |
| 62 | 60 |
| 63 // WebM File Header. This is prepended to the INFO & TRACKS | 61 // WebM File Header. This is prepended to the INFO & TRACKS |
| 64 // data passed to Init() before handing it to FFmpeg. Essentially | 62 // data passed to Init() before handing it to FFmpeg. Essentially |
| 65 // we are making the INFO & TRACKS data look like a small WebM | 63 // we are making the INFO & TRACKS data look like a small WebM |
| 66 // file so we can use FFmpeg to initialize the AVFormatContext. | 64 // file so we can use FFmpeg to initialize the AVFormatContext. |
| 67 const uint8 FFmpegConfigHelper::kWebMHeader[] = { | 65 const uint8 FFmpegConfigHelper::kWebMHeader[] = { |
| 68 0x1A, 0x45, 0xDF, 0xA3, 0x9F, // EBML (size = 0x1f) | 66 0x1A, 0x45, 0xDF, 0xA3, 0x9F, // EBML (size = 0x1f) |
| (...skipping 11 matching lines...) Expand all Loading... |
| 80 }; | 78 }; |
| 81 | 79 |
| 82 // Offset of the segment size field in kWebMHeader. Used to update | 80 // Offset of the segment size field in kWebMHeader. Used to update |
| 83 // the segment size field before handing the buffer to FFmpeg. | 81 // the segment size field before handing the buffer to FFmpeg. |
| 84 const int FFmpegConfigHelper::kSegmentSizeOffset = sizeof(kWebMHeader) - 8; | 82 const int FFmpegConfigHelper::kSegmentSizeOffset = sizeof(kWebMHeader) - 8; |
| 85 | 83 |
| 86 const uint8 FFmpegConfigHelper::kEmptyCluster[] = { | 84 const uint8 FFmpegConfigHelper::kEmptyCluster[] = { |
| 87 0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0) | 85 0x1F, 0x43, 0xB6, 0x75, 0x80 // CLUSTER (size = 0) |
| 88 }; | 86 }; |
| 89 | 87 |
| 90 FFmpegConfigHelper::FFmpegConfigHelper() : format_context_(NULL) {} | 88 FFmpegConfigHelper::FFmpegConfigHelper() {} |
| 91 | 89 |
| 92 FFmpegConfigHelper::~FFmpegConfigHelper() { | 90 FFmpegConfigHelper::~FFmpegConfigHelper() { |
| 93 if (!format_context_) | |
| 94 return; | |
| 95 | |
| 96 DestroyAVFormatContext(format_context_); | |
| 97 format_context_ = NULL; | |
| 98 | |
| 99 if (url_protocol_.get()) { | 91 if (url_protocol_.get()) { |
| 100 FFmpegGlue::GetInstance()->RemoveProtocol(url_protocol_.get()); | |
| 101 url_protocol_.reset(); | 92 url_protocol_.reset(); |
| 102 url_protocol_buffer_.reset(); | 93 url_protocol_buffer_.reset(); |
| 103 } | 94 } |
| 95 |
| 96 if (glue_.get()) |
| 97 glue_.reset(); |
| 104 } | 98 } |
| 105 | 99 |
| 106 bool FFmpegConfigHelper::Parse(const uint8* data, int size) { | 100 bool FFmpegConfigHelper::Parse(const uint8* data, int size) { |
| 107 format_context_ = CreateFormatContext(data, size); | 101 return OpenFormatContext(data, size) && SetupStreamConfigs(); |
| 108 return format_context_ && SetupStreamConfigs(); | |
| 109 } | 102 } |
| 110 | 103 |
| 111 const AudioDecoderConfig& FFmpegConfigHelper::audio_config() const { | 104 const AudioDecoderConfig& FFmpegConfigHelper::audio_config() const { |
| 112 return audio_config_; | 105 return audio_config_; |
| 113 } | 106 } |
| 114 | 107 |
| 115 const VideoDecoderConfig& FFmpegConfigHelper::video_config() const { | 108 const VideoDecoderConfig& FFmpegConfigHelper::video_config() const { |
| 116 return video_config_; | 109 return video_config_; |
| 117 } | 110 } |
| 118 | 111 |
| 119 AVFormatContext* FFmpegConfigHelper::CreateFormatContext(const uint8* data, | 112 bool FFmpegConfigHelper::OpenFormatContext(const uint8* data, int size) { |
| 120 int size) { | |
| 121 DCHECK(!url_protocol_.get()); | 113 DCHECK(!url_protocol_.get()); |
| 122 DCHECK(!url_protocol_buffer_.get()); | 114 DCHECK(!url_protocol_buffer_.get()); |
| 115 DCHECK(!glue_.get()); |
| 123 | 116 |
| 124 int segment_size = size + sizeof(kEmptyCluster); | 117 int segment_size = size + sizeof(kEmptyCluster); |
| 125 int buf_size = sizeof(kWebMHeader) + segment_size; | 118 int buf_size = sizeof(kWebMHeader) + segment_size; |
| 126 url_protocol_buffer_.reset(new uint8[buf_size]); | 119 url_protocol_buffer_.reset(new uint8[buf_size]); |
| 127 uint8* buf = url_protocol_buffer_.get(); | 120 uint8* buf = url_protocol_buffer_.get(); |
| 128 memcpy(buf, kWebMHeader, sizeof(kWebMHeader)); | 121 memcpy(buf, kWebMHeader, sizeof(kWebMHeader)); |
| 129 memcpy(buf + sizeof(kWebMHeader), data, size); | 122 memcpy(buf + sizeof(kWebMHeader), data, size); |
| 130 memcpy(buf + sizeof(kWebMHeader) + size, kEmptyCluster, | 123 memcpy(buf + sizeof(kWebMHeader) + size, kEmptyCluster, |
| 131 sizeof(kEmptyCluster)); | 124 sizeof(kEmptyCluster)); |
| 132 | 125 |
| 133 // Update the segment size in the buffer. | 126 // Update the segment size in the buffer. |
| 134 int64 tmp = (segment_size & GG_LONGLONG(0x00FFFFFFFFFFFFFF)) | | 127 int64 tmp = (segment_size & GG_LONGLONG(0x00FFFFFFFFFFFFFF)) | |
| 135 GG_LONGLONG(0x0100000000000000); | 128 GG_LONGLONG(0x0100000000000000); |
| 136 for (int i = 0; i < 8; i++) { | 129 for (int i = 0; i < 8; i++) { |
| 137 buf[kSegmentSizeOffset + i] = (tmp >> (8 * (7 - i))) & 0xff; | 130 buf[kSegmentSizeOffset + i] = (tmp >> (8 * (7 - i))) & 0xff; |
| 138 } | 131 } |
| 139 | 132 |
| 140 url_protocol_.reset(new InMemoryUrlProtocol(buf, buf_size, true)); | 133 url_protocol_.reset(new InMemoryUrlProtocol(buf, buf_size, true)); |
| 141 std::string key = FFmpegGlue::GetInstance()->AddProtocol(url_protocol_.get()); | 134 glue_.reset(new FFmpegGlue(url_protocol_.get())); |
| 142 | 135 |
| 143 // Open FFmpeg AVFormatContext. | 136 // Open FFmpeg AVFormatContext. |
| 144 AVFormatContext* context = NULL; | 137 return glue_->OpenContext(); |
| 145 int result = avformat_open_input(&context, key.c_str(), NULL, NULL); | |
| 146 | |
| 147 if (result < 0) | |
| 148 return NULL; | |
| 149 | |
| 150 return context; | |
| 151 } | 138 } |
| 152 | 139 |
| 153 bool FFmpegConfigHelper::SetupStreamConfigs() { | 140 bool FFmpegConfigHelper::SetupStreamConfigs() { |
| 154 int result = avformat_find_stream_info(format_context_, NULL); | 141 AVFormatContext* format_context = glue_->format_context(); |
| 142 int result = avformat_find_stream_info(format_context, NULL); |
| 155 | 143 |
| 156 if (result < 0) | 144 if (result < 0) |
| 157 return false; | 145 return false; |
| 158 | 146 |
| 159 bool no_supported_streams = true; | 147 bool no_supported_streams = true; |
| 160 for (size_t i = 0; i < format_context_->nb_streams; ++i) { | 148 for (size_t i = 0; i < format_context->nb_streams; ++i) { |
| 161 AVStream* stream = format_context_->streams[i]; | 149 AVStream* stream = format_context->streams[i]; |
| 162 AVCodecContext* codec_context = stream->codec; | 150 AVCodecContext* codec_context = stream->codec; |
| 163 AVMediaType codec_type = codec_context->codec_type; | 151 AVMediaType codec_type = codec_context->codec_type; |
| 164 | 152 |
| 165 if (codec_type == AVMEDIA_TYPE_AUDIO && | 153 if (codec_type == AVMEDIA_TYPE_AUDIO && |
| 166 stream->codec->codec_id == CODEC_ID_VORBIS && | 154 stream->codec->codec_id == CODEC_ID_VORBIS && |
| 167 !audio_config_.IsValidConfig()) { | 155 !audio_config_.IsValidConfig()) { |
| 168 AVCodecContextToAudioDecoderConfig(stream->codec, &audio_config_); | 156 AVCodecContextToAudioDecoderConfig(stream->codec, &audio_config_); |
| 169 no_supported_streams = false; | 157 no_supported_streams = false; |
| 170 continue; | 158 continue; |
| 171 } | 159 } |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 if (!video_buffers.empty() && !video_cb_.Run(video_buffers)) | 437 if (!video_buffers.empty() && !video_cb_.Run(video_buffers)) |
| 450 return -1; | 438 return -1; |
| 451 | 439 |
| 452 if (cluster_ended) | 440 if (cluster_ended) |
| 453 end_of_segment_cb_.Run(); | 441 end_of_segment_cb_.Run(); |
| 454 | 442 |
| 455 return bytes_parsed; | 443 return bytes_parsed; |
| 456 } | 444 } |
| 457 | 445 |
| 458 } // namespace media | 446 } // namespace media |
| OLD | NEW |