Chromium Code Reviews| 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/filters/ffmpeg_demuxer.h" | 5 #include "media/filters/ffmpeg_demuxer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <set> | 9 #include <set> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 51 | 51 |
| 52 namespace { | 52 namespace { |
| 53 | 53 |
| 54 void SetAVStreamDiscard(AVStream* stream, AVDiscard discard) { | 54 void SetAVStreamDiscard(AVStream* stream, AVDiscard discard) { |
| 55 DCHECK(stream); | 55 DCHECK(stream); |
| 56 stream->discard = discard; | 56 stream->discard = discard; |
| 57 } | 57 } |
| 58 | 58 |
| 59 } // namespace | 59 } // namespace |
| 60 | 60 |
| 61 static base::Time ExtractTimelineOffset(AVFormatContext* format_context) { | 61 static base::Time ExtractTimelineOffset( |
| 62 if (strstr(format_context->iformat->name, "webm") || | 62 container_names::MediaContainerName container, |
| 63 strstr(format_context->iformat->name, "matroska")) { | 63 const AVFormatContext* format_context) { |
| 64 if (container == container_names::CONTAINER_WEBM) { | |
| 64 const AVDictionaryEntry* entry = | 65 const AVDictionaryEntry* entry = |
| 65 av_dict_get(format_context->metadata, "creation_time", NULL, 0); | 66 av_dict_get(format_context->metadata, "creation_time", NULL, 0); |
| 66 | 67 |
| 67 base::Time timeline_offset; | 68 base::Time timeline_offset; |
| 68 | 69 |
| 69 // FFmpegDemuxerTests assume base::Time::FromUTCString() is used here. | 70 // FFmpegDemuxerTests assume base::Time::FromUTCString() is used here. |
| 70 if (entry != NULL && entry->value != NULL && | 71 if (entry != NULL && entry->value != NULL && |
| 71 base::Time::FromUTCString(entry->value, &timeline_offset)) { | 72 base::Time::FromUTCString(entry->value, &timeline_offset)) { |
| 72 return timeline_offset; | 73 return timeline_offset; |
| 73 } | 74 } |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 153 if (ToAudioSampleRate(audio_config.samples_per_second(), &asr)) { | 154 if (ToAudioSampleRate(audio_config.samples_per_second(), &asr)) { |
| 154 UMA_HISTOGRAM_ENUMERATION("Media.AudioSamplesPerSecond", asr, | 155 UMA_HISTOGRAM_ENUMERATION("Media.AudioSamplesPerSecond", asr, |
| 155 kAudioSampleRateMax + 1); | 156 kAudioSampleRateMax + 1); |
| 156 } else { | 157 } else { |
| 157 UMA_HISTOGRAM_COUNTS("Media.AudioSamplesPerSecondUnexpected", | 158 UMA_HISTOGRAM_COUNTS("Media.AudioSamplesPerSecondUnexpected", |
| 158 audio_config.samples_per_second()); | 159 audio_config.samples_per_second()); |
| 159 } | 160 } |
| 160 } | 161 } |
| 161 | 162 |
| 162 // Record video decoder config UMA stats corresponding to a src= playback. | 163 // Record video decoder config UMA stats corresponding to a src= playback. |
| 163 static void RecordVideoCodecStats(const VideoDecoderConfig& video_config, | 164 static void RecordVideoCodecStats(container_names::MediaContainerName container, |
| 165 const VideoDecoderConfig& video_config, | |
| 164 AVColorRange color_range, | 166 AVColorRange color_range, |
| 165 MediaLog* media_log) { | 167 MediaLog* media_log) { |
| 166 media_log->RecordRapporWithSecurityOrigin("Media.OriginUrl.SRC.VideoCodec." + | 168 media_log->RecordRapporWithSecurityOrigin("Media.OriginUrl.SRC.VideoCodec." + |
| 167 GetCodecName(video_config.codec())); | 169 GetCodecName(video_config.codec())); |
| 168 | 170 |
| 169 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodec", video_config.codec(), | 171 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodec", video_config.codec(), |
| 170 kVideoCodecMax + 1); | 172 kVideoCodecMax + 1); |
| 173 if (container == container_names::CONTAINER_MOV) { | |
| 174 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodec.MP4", video_config.codec(), | |
|
xhwang
2017/05/03 05:33:45
Shall we just name this Media.SRC.VideoCodec.MP4 t
wolenetz
2017/05/03 20:48:23
I don't recall the previous reason why we didn't d
| |
| 175 kVideoCodecMax + 1); | |
| 176 } else if (container == container_names::CONTAINER_WEBM) { | |
| 177 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodec.WebM", video_config.codec(), | |
| 178 kVideoCodecMax + 1); | |
| 179 } | |
| 171 | 180 |
| 172 // Drop UNKNOWN because U_H_E() uses one bucket for all values less than 1. | 181 // Drop UNKNOWN because U_H_E() uses one bucket for all values less than 1. |
| 173 if (video_config.profile() >= 0) { | 182 if (video_config.profile() >= 0) { |
| 174 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodecProfile", video_config.profile(), | 183 UMA_HISTOGRAM_ENUMERATION("Media.VideoCodecProfile", video_config.profile(), |
| 175 VIDEO_CODEC_PROFILE_MAX + 1); | 184 VIDEO_CODEC_PROFILE_MAX + 1); |
| 176 } | 185 } |
| 177 UMA_HISTOGRAM_COUNTS_10000("Media.VideoVisibleWidth", | 186 UMA_HISTOGRAM_COUNTS_10000("Media.VideoVisibleWidth", |
| 178 video_config.visible_rect().width()); | 187 video_config.visible_rect().width()); |
| 179 UmaHistogramAspectRatio("Media.VideoVisibleAspectRatio", | 188 UmaHistogramAspectRatio("Media.VideoVisibleAspectRatio", |
| 180 video_config.visible_rect()); | 189 video_config.visible_rect()); |
| (...skipping 1154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1335 | 1344 |
| 1336 // This AVStream does not successfully convert. | 1345 // This AVStream does not successfully convert. |
| 1337 continue; | 1346 continue; |
| 1338 } | 1347 } |
| 1339 | 1348 |
| 1340 StreamParser::TrackId track_id = stream->id; | 1349 StreamParser::TrackId track_id = stream->id; |
| 1341 std::string track_label = streams_[i]->GetMetadata("handler_name"); | 1350 std::string track_label = streams_[i]->GetMetadata("handler_name"); |
| 1342 std::string track_language = streams_[i]->GetMetadata("language"); | 1351 std::string track_language = streams_[i]->GetMetadata("language"); |
| 1343 | 1352 |
| 1344 // Some metadata is named differently in FFmpeg for webm files. | 1353 // Some metadata is named differently in FFmpeg for webm files. |
| 1345 if (strstr(format_context->iformat->name, "webm") || | 1354 if (glue_->container() == container_names::CONTAINER_WEBM) { |
| 1346 strstr(format_context->iformat->name, "matroska")) { | |
| 1347 // TODO(servolk): FFmpeg doesn't set stream->id correctly for webm files. | 1355 // TODO(servolk): FFmpeg doesn't set stream->id correctly for webm files. |
| 1348 // Need to fix that and use it as track id. crbug.com/323183 | 1356 // Need to fix that and use it as track id. crbug.com/323183 |
| 1349 track_id = | 1357 track_id = |
| 1350 static_cast<StreamParser::TrackId>(media_tracks->tracks().size() + 1); | 1358 static_cast<StreamParser::TrackId>(media_tracks->tracks().size() + 1); |
| 1351 track_label = streams_[i]->GetMetadata("title"); | 1359 track_label = streams_[i]->GetMetadata("title"); |
| 1352 } | 1360 } |
| 1353 | 1361 |
| 1354 if (codec_type == AVMEDIA_TYPE_AUDIO) { | 1362 if (codec_type == AVMEDIA_TYPE_AUDIO) { |
| 1355 streams_[i]->SetEnabled(detected_audio_track_count == 1, | 1363 streams_[i]->SetEnabled(detected_audio_track_count == 1, |
| 1356 base::TimeDelta()); | 1364 base::TimeDelta()); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1378 | 1386 |
| 1379 media_track = media_tracks->AddAudioTrack(audio_config, track_id, "main", | 1387 media_track = media_tracks->AddAudioTrack(audio_config, track_id, "main", |
| 1380 track_label, track_language); | 1388 track_label, track_language); |
| 1381 media_track->set_id(base::UintToString(track_id)); | 1389 media_track->set_id(base::UintToString(track_id)); |
| 1382 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == | 1390 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == |
| 1383 track_id_to_demux_stream_map_.end()); | 1391 track_id_to_demux_stream_map_.end()); |
| 1384 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); | 1392 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); |
| 1385 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { | 1393 } else if (codec_type == AVMEDIA_TYPE_VIDEO) { |
| 1386 VideoDecoderConfig video_config = streams_[i]->video_decoder_config(); | 1394 VideoDecoderConfig video_config = streams_[i]->video_decoder_config(); |
| 1387 | 1395 |
| 1388 RecordVideoCodecStats(video_config, stream->codecpar->color_range, | 1396 RecordVideoCodecStats(glue_->container(), video_config, |
| 1389 media_log_); | 1397 stream->codecpar->color_range, media_log_); |
| 1390 | 1398 |
| 1391 media_track = media_tracks->AddVideoTrack(video_config, track_id, "main", | 1399 media_track = media_tracks->AddVideoTrack(video_config, track_id, "main", |
| 1392 track_label, track_language); | 1400 track_label, track_language); |
| 1393 media_track->set_id(base::UintToString(track_id)); | 1401 media_track->set_id(base::UintToString(track_id)); |
| 1394 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == | 1402 DCHECK(track_id_to_demux_stream_map_.find(media_track->id()) == |
| 1395 track_id_to_demux_stream_map_.end()); | 1403 track_id_to_demux_stream_map_.end()); |
| 1396 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); | 1404 track_id_to_demux_stream_map_[media_track->id()] = streams_[i].get(); |
| 1397 } | 1405 } |
| 1398 | 1406 |
| 1399 max_duration = std::max(max_duration, streams_[i]->duration()); | 1407 max_duration = std::max(max_duration, streams_[i]->duration()); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1447 // | 1455 // |
| 1448 // FFmpeg's use of negative timestamps for opus pre-skip is nonstandard, but | 1456 // FFmpeg's use of negative timestamps for opus pre-skip is nonstandard, but |
| 1449 // for more information on pre-skip see section 4.2 of the Ogg Opus spec: | 1457 // for more information on pre-skip see section 4.2 of the Ogg Opus spec: |
| 1450 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-4.2 | 1458 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-08#section-4.2 |
| 1451 for (const auto& stream : streams_) { | 1459 for (const auto& stream : streams_) { |
| 1452 if (!stream || stream->type() != DemuxerStream::AUDIO) | 1460 if (!stream || stream->type() != DemuxerStream::AUDIO) |
| 1453 continue; | 1461 continue; |
| 1454 const AVStream* audio_stream = stream->av_stream(); | 1462 const AVStream* audio_stream = stream->av_stream(); |
| 1455 DCHECK(audio_stream); | 1463 DCHECK(audio_stream); |
| 1456 if (audio_stream->codecpar->codec_id == AV_CODEC_ID_OPUS || | 1464 if (audio_stream->codecpar->codec_id == AV_CODEC_ID_OPUS || |
| 1457 (strcmp(format_context->iformat->name, "ogg") == 0 && | 1465 (glue_->container() == container_names::CONTAINER_OGG && |
| 1458 audio_stream->codecpar->codec_id == AV_CODEC_ID_VORBIS)) { | 1466 audio_stream->codecpar->codec_id == AV_CODEC_ID_VORBIS)) { |
| 1459 for (size_t i = 0; i < streams_.size(); ++i) { | 1467 for (size_t i = 0; i < streams_.size(); ++i) { |
| 1460 if (!streams_[i]) | 1468 if (!streams_[i]) |
| 1461 continue; | 1469 continue; |
| 1462 streams_[i]->enable_negative_timestamp_fixups(); | 1470 streams_[i]->enable_negative_timestamp_fixups(); |
| 1463 | 1471 |
| 1464 // Fixup the seeking information to avoid selecting the audio stream | 1472 // Fixup the seeking information to avoid selecting the audio stream |
| 1465 // simply because it has a lower starting time. | 1473 // simply because it has a lower starting time. |
| 1466 if (streams_[i]->av_stream() == audio_stream && | 1474 if (streams_[i]->av_stream() == audio_stream && |
| 1467 streams_[i]->start_time() < base::TimeDelta()) { | 1475 streams_[i]->start_time() < base::TimeDelta()) { |
| 1468 streams_[i]->set_start_time(base::TimeDelta()); | 1476 streams_[i]->set_start_time(base::TimeDelta()); |
| 1469 } | 1477 } |
| 1470 } | 1478 } |
| 1471 } | 1479 } |
| 1472 } | 1480 } |
| 1473 | 1481 |
| 1474 // If no start time could be determined, default to zero. | 1482 // If no start time could be determined, default to zero. |
| 1475 if (start_time_ == kInfiniteDuration) { | 1483 if (start_time_ == kInfiniteDuration) { |
| 1476 start_time_ = base::TimeDelta(); | 1484 start_time_ = base::TimeDelta(); |
| 1477 } | 1485 } |
| 1478 | 1486 |
| 1479 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS | 1487 // MPEG-4 B-frames cause grief for a simple container like AVI. Enable PTS |
| 1480 // generation so we always get timestamps, see http://crbug.com/169570 | 1488 // generation so we always get timestamps, see http://crbug.com/169570 |
| 1481 if (strcmp(format_context->iformat->name, "avi") == 0) | 1489 if (glue_->container() == container_names::CONTAINER_AVI) |
| 1482 format_context->flags |= AVFMT_FLAG_GENPTS; | 1490 format_context->flags |= AVFMT_FLAG_GENPTS; |
| 1483 | 1491 |
| 1484 // For testing purposes, don't overwrite the timeline offset if set already. | 1492 // For testing purposes, don't overwrite the timeline offset if set already. |
| 1485 if (timeline_offset_.is_null()) | 1493 if (timeline_offset_.is_null()) { |
| 1486 timeline_offset_ = ExtractTimelineOffset(format_context); | 1494 timeline_offset_ = |
| 1495 ExtractTimelineOffset(glue_->container(), format_context); | |
| 1496 } | |
| 1487 | 1497 |
| 1488 // Since we're shifting the externally visible start time to zero, we need to | 1498 // Since we're shifting the externally visible start time to zero, we need to |
| 1489 // adjust the timeline offset to compensate. | 1499 // adjust the timeline offset to compensate. |
| 1490 if (!timeline_offset_.is_null() && start_time_ < base::TimeDelta()) | 1500 if (!timeline_offset_.is_null() && start_time_ < base::TimeDelta()) |
| 1491 timeline_offset_ += start_time_; | 1501 timeline_offset_ += start_time_; |
| 1492 | 1502 |
| 1493 if (max_duration == kInfiniteDuration && !timeline_offset_.is_null()) { | 1503 if (max_duration == kInfiniteDuration && !timeline_offset_.is_null()) { |
| 1494 SetLiveness(DemuxerStream::LIVENESS_LIVE); | 1504 SetLiveness(DemuxerStream::LIVENESS_LIVE); |
| 1495 } else if (max_duration != kInfiniteDuration) { | 1505 } else if (max_duration != kInfiniteDuration) { |
| 1496 SetLiveness(DemuxerStream::LIVENESS_RECORDED); | 1506 SetLiveness(DemuxerStream::LIVENESS_RECORDED); |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1881 | 1891 |
| 1882 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { | 1892 void FFmpegDemuxer::SetLiveness(DemuxerStream::Liveness liveness) { |
| 1883 DCHECK(task_runner_->BelongsToCurrentThread()); | 1893 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 1884 for (const auto& stream : streams_) { | 1894 for (const auto& stream : streams_) { |
| 1885 if (stream) | 1895 if (stream) |
| 1886 stream->SetLiveness(liveness); | 1896 stream->SetLiveness(liveness); |
| 1887 } | 1897 } |
| 1888 } | 1898 } |
| 1889 | 1899 |
| 1890 } // namespace media | 1900 } // namespace media |
| OLD | NEW |