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/ffmpeg/ffmpeg_common.h" | 5 #include "media/ffmpeg/ffmpeg_common.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/sha1.h" | 8 #include "base/sha1.h" |
9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
10 #include "base/strings/string_split.h" | 10 #include "base/strings/string_split.h" |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 break; | 398 break; |
399 default: | 399 default: |
400 DCHECK_EQ(av_get_bytes_per_sample(codec_context->sample_fmt) * 8, | 400 DCHECK_EQ(av_get_bytes_per_sample(codec_context->sample_fmt) * 8, |
401 config->bits_per_channel()); | 401 config->bits_per_channel()); |
402 break; | 402 break; |
403 } | 403 } |
404 | 404 |
405 return true; | 405 return true; |
406 } | 406 } |
407 | 407 |
| 408 std::unique_ptr<AVCodecContext, ScopedPtrAVFreeContext> |
| 409 AVStreamToAVCodecContext(const AVStream* stream) { |
| 410 std::unique_ptr<AVCodecContext, ScopedPtrAVFreeContext> codec_context( |
| 411 avcodec_alloc_context3(nullptr)); |
| 412 if (avcodec_parameters_to_context(codec_context.get(), stream->codecpar) < |
| 413 0) { |
| 414 return nullptr; |
| 415 } |
| 416 |
| 417 return codec_context; |
| 418 } |
| 419 |
408 bool AVStreamToAudioDecoderConfig(const AVStream* stream, | 420 bool AVStreamToAudioDecoderConfig(const AVStream* stream, |
409 AudioDecoderConfig* config) { | 421 AudioDecoderConfig* config) { |
| 422 std::unique_ptr<AVCodecContext, ScopedPtrAVFreeContext> codec_context( |
| 423 AVStreamToAVCodecContext(stream)); |
| 424 if (!codec_context) |
| 425 return false; |
| 426 |
410 return AVCodecContextToAudioDecoderConfig( | 427 return AVCodecContextToAudioDecoderConfig( |
411 stream->codec, GetEncryptionScheme(stream), config); | 428 codec_context.get(), GetEncryptionScheme(stream), config); |
412 } | 429 } |
413 | 430 |
414 void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config, | 431 void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config, |
415 AVCodecContext* codec_context) { | 432 AVCodecContext* codec_context) { |
416 codec_context->codec_type = AVMEDIA_TYPE_AUDIO; | 433 codec_context->codec_type = AVMEDIA_TYPE_AUDIO; |
417 codec_context->codec_id = AudioCodecToCodecID(config.codec(), | 434 codec_context->codec_id = AudioCodecToCodecID(config.codec(), |
418 config.sample_format()); | 435 config.sample_format()); |
419 codec_context->sample_fmt = SampleFormatToAVSampleFormat( | 436 codec_context->sample_fmt = SampleFormatToAVSampleFormat( |
420 config.sample_format()); | 437 config.sample_format()); |
421 | 438 |
(...skipping 12 matching lines...) Expand all Loading... |
434 av_malloc(config.extra_data().size() + FF_INPUT_BUFFER_PADDING_SIZE)); | 451 av_malloc(config.extra_data().size() + FF_INPUT_BUFFER_PADDING_SIZE)); |
435 memcpy(codec_context->extradata, &config.extra_data()[0], | 452 memcpy(codec_context->extradata, &config.extra_data()[0], |
436 config.extra_data().size()); | 453 config.extra_data().size()); |
437 memset(codec_context->extradata + config.extra_data().size(), '\0', | 454 memset(codec_context->extradata + config.extra_data().size(), '\0', |
438 FF_INPUT_BUFFER_PADDING_SIZE); | 455 FF_INPUT_BUFFER_PADDING_SIZE); |
439 } | 456 } |
440 } | 457 } |
441 | 458 |
442 bool AVStreamToVideoDecoderConfig(const AVStream* stream, | 459 bool AVStreamToVideoDecoderConfig(const AVStream* stream, |
443 VideoDecoderConfig* config) { | 460 VideoDecoderConfig* config) { |
444 // Anticipating AVStream.codec.coded_{width,height} will be inaccessible in | 461 std::unique_ptr<AVCodecContext, ScopedPtrAVFreeContext> codec_context( |
445 // ffmpeg soon, just use the width and height, padded below, as hints of the | 462 AVStreamToAVCodecContext(stream)); |
446 // coded size. | 463 if (!codec_context) |
447 gfx::Size coded_size(stream->codec->width, stream->codec->height); | 464 return false; |
| 465 |
| 466 // AVStream.codec->coded_{width,height} access is deprecated in ffmpeg. |
| 467 // Use just the width and height as hints of coded size. |
| 468 gfx::Size coded_size(codec_context->width, codec_context->height); |
448 | 469 |
449 // TODO(vrk): This assumes decoded frame data starts at (0, 0), which is true | 470 // TODO(vrk): This assumes decoded frame data starts at (0, 0), which is true |
450 // for now, but may not always be true forever. Fix this in the future. | 471 // for now, but may not always be true forever. Fix this in the future. |
451 gfx::Rect visible_rect(stream->codec->width, stream->codec->height); | 472 gfx::Rect visible_rect(codec_context->width, codec_context->height); |
452 | 473 |
453 AVRational aspect_ratio = { 1, 1 }; | 474 AVRational aspect_ratio = { 1, 1 }; |
454 if (stream->sample_aspect_ratio.num) | 475 if (stream->sample_aspect_ratio.num) |
455 aspect_ratio = stream->sample_aspect_ratio; | 476 aspect_ratio = stream->sample_aspect_ratio; |
456 else if (stream->codec->sample_aspect_ratio.num) | 477 else if (codec_context->sample_aspect_ratio.num) |
457 aspect_ratio = stream->codec->sample_aspect_ratio; | 478 aspect_ratio = codec_context->sample_aspect_ratio; |
458 | 479 |
459 VideoCodec codec = CodecIDToVideoCodec(stream->codec->codec_id); | 480 VideoCodec codec = CodecIDToVideoCodec(codec_context->codec_id); |
460 | 481 |
461 VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; | 482 VideoCodecProfile profile = VIDEO_CODEC_PROFILE_UNKNOWN; |
462 if (codec == kCodecVP8) | 483 if (codec == kCodecVP8) |
463 profile = VP8PROFILE_ANY; | 484 profile = VP8PROFILE_ANY; |
464 else if (codec == kCodecVP9) | 485 else if (codec == kCodecVP9) |
465 // TODO(servolk): Find a way to obtain actual VP9 profile from FFmpeg. | 486 // TODO(servolk): Find a way to obtain actual VP9 profile from FFmpeg. |
466 // crbug.com/592074 | 487 // crbug.com/592074 |
467 profile = VP9PROFILE_PROFILE0; | 488 profile = VP9PROFILE_PROFILE0; |
468 else | 489 else |
469 profile = ProfileIDToVideoCodecProfile(stream->codec->profile); | 490 profile = ProfileIDToVideoCodecProfile(codec_context->profile); |
470 | 491 |
471 // Without the FFmpeg h264 decoder, AVFormat is unable to get the profile, so | 492 // Without the FFmpeg h264 decoder, AVFormat is unable to get the profile, so |
472 // default to baseline and let the VDA fail later if it doesn't support the | 493 // default to baseline and let the VDA fail later if it doesn't support the |
473 // real profile. This is alright because if the FFmpeg h264 decoder isn't | 494 // real profile. This is alright because if the FFmpeg h264 decoder isn't |
474 // enabled, there is no fallback if the VDA fails. | 495 // enabled, there is no fallback if the VDA fails. |
475 #if defined(DISABLE_FFMPEG_VIDEO_DECODERS) | 496 #if defined(DISABLE_FFMPEG_VIDEO_DECODERS) |
476 if (codec == kCodecH264) | 497 if (codec == kCodecH264) |
477 profile = H264PROFILE_BASELINE; | 498 profile = H264PROFILE_BASELINE; |
478 #endif | 499 #endif |
479 | 500 |
480 gfx::Size natural_size = GetNaturalSize( | 501 gfx::Size natural_size = GetNaturalSize( |
481 visible_rect.size(), aspect_ratio.num, aspect_ratio.den); | 502 visible_rect.size(), aspect_ratio.num, aspect_ratio.den); |
482 | 503 |
483 VideoPixelFormat format = | 504 VideoPixelFormat format = |
484 AVPixelFormatToVideoPixelFormat(stream->codec->pix_fmt); | 505 AVPixelFormatToVideoPixelFormat(codec_context->pix_fmt); |
485 // The format and coded size may be unknown if FFmpeg is compiled without | 506 // The format and coded size may be unknown if FFmpeg is compiled without |
486 // video decoders. | 507 // video decoders. |
487 #if defined(DISABLE_FFMPEG_VIDEO_DECODERS) | 508 #if defined(DISABLE_FFMPEG_VIDEO_DECODERS) |
488 if (format == PIXEL_FORMAT_UNKNOWN) | 509 if (format == PIXEL_FORMAT_UNKNOWN) |
489 format = PIXEL_FORMAT_YV12; | 510 format = PIXEL_FORMAT_YV12; |
490 if (coded_size == gfx::Size(0, 0)) | 511 if (coded_size == gfx::Size(0, 0)) |
491 coded_size = visible_rect.size(); | 512 coded_size = visible_rect.size(); |
492 #endif | 513 #endif |
493 | 514 |
494 if (codec == kCodecVP9) { | 515 if (codec == kCodecVP9) { |
495 // TODO(tomfinegan): libavcodec doesn't know about VP9. | 516 // TODO(tomfinegan): libavcodec doesn't know about VP9. |
496 format = PIXEL_FORMAT_YV12; | 517 format = PIXEL_FORMAT_YV12; |
497 coded_size = visible_rect.size(); | 518 coded_size = visible_rect.size(); |
498 } | 519 } |
499 | 520 |
500 // Pad out |coded_size| for subsampled YUV formats. | 521 // Pad out |coded_size| for subsampled YUV formats. |
501 if (format != PIXEL_FORMAT_YV24) { | 522 if (format != PIXEL_FORMAT_YV24) { |
502 coded_size.set_width((coded_size.width() + 1) / 2 * 2); | 523 coded_size.set_width((coded_size.width() + 1) / 2 * 2); |
503 if (format != PIXEL_FORMAT_YV16) | 524 if (format != PIXEL_FORMAT_YV16) |
504 coded_size.set_height((coded_size.height() + 1) / 2 * 2); | 525 coded_size.set_height((coded_size.height() + 1) / 2 * 2); |
505 } | 526 } |
506 | 527 |
507 AVDictionaryEntry* webm_alpha = | 528 AVDictionaryEntry* webm_alpha = |
508 av_dict_get(stream->metadata, "alpha_mode", nullptr, 0); | 529 av_dict_get(stream->metadata, "alpha_mode", nullptr, 0); |
509 if (webm_alpha && !strcmp(webm_alpha->value, "1")) { | 530 if (webm_alpha && !strcmp(webm_alpha->value, "1")) { |
510 format = PIXEL_FORMAT_YV12A; | 531 format = PIXEL_FORMAT_YV12A; |
511 } | 532 } |
512 | 533 |
513 // Prefer the color space found by libavcodec if available. | 534 // Prefer the color space found by libavcodec if available. |
514 ColorSpace color_space = AVColorSpaceToColorSpace(stream->codec->colorspace, | 535 ColorSpace color_space = AVColorSpaceToColorSpace(codec_context->colorspace, |
515 stream->codec->color_range); | 536 codec_context->color_range); |
516 if (color_space == COLOR_SPACE_UNSPECIFIED) { | 537 if (color_space == COLOR_SPACE_UNSPECIFIED) { |
517 // Otherwise, assume that SD video is usually Rec.601, and HD is usually | 538 // Otherwise, assume that SD video is usually Rec.601, and HD is usually |
518 // Rec.709. | 539 // Rec.709. |
519 color_space = (natural_size.height() < 720) ? COLOR_SPACE_SD_REC601 | 540 color_space = (natural_size.height() < 720) ? COLOR_SPACE_SD_REC601 |
520 : COLOR_SPACE_HD_REC709; | 541 : COLOR_SPACE_HD_REC709; |
521 } | 542 } |
522 | 543 |
523 // AVStream occasionally has invalid extra data. See http://crbug.com/517163 | 544 // AVCodecContext occasionally has invalid extra data. See |
524 if ((stream->codec->extradata_size == 0) != | 545 // http://crbug.com/517163 |
525 (stream->codec->extradata == nullptr)) { | 546 if (codec_context->extradata != nullptr && |
526 LOG(ERROR) << __func__ | 547 codec_context->extradata_size == 0) { |
527 << (stream->codec->extradata == nullptr ? " NULL" : " Non-Null") | 548 LOG(ERROR) << __func__ << " Non-Null extra data cannot have size of 0."; |
528 << " extra data cannot have size of " | |
529 << stream->codec->extradata_size << "."; | |
530 return false; | 549 return false; |
531 } | 550 } |
| 551 CHECK_EQ(codec_context->extradata == nullptr, |
| 552 codec_context->extradata_size == 0); |
532 | 553 |
533 std::vector<uint8_t> extra_data; | 554 std::vector<uint8_t> extra_data; |
534 if (stream->codec->extradata_size > 0) { | 555 if (codec_context->extradata_size > 0) { |
535 extra_data.assign(stream->codec->extradata, | 556 extra_data.assign(codec_context->extradata, |
536 stream->codec->extradata + stream->codec->extradata_size); | 557 codec_context->extradata + codec_context->extradata_size); |
537 } | 558 } |
538 config->Initialize(codec, profile, format, color_space, coded_size, | 559 config->Initialize(codec, profile, format, color_space, coded_size, |
539 visible_rect, natural_size, extra_data, | 560 visible_rect, natural_size, extra_data, |
540 GetEncryptionScheme(stream)); | 561 GetEncryptionScheme(stream)); |
541 return true; | 562 return true; |
542 } | 563 } |
543 | 564 |
544 void VideoDecoderConfigToAVCodecContext( | 565 void VideoDecoderConfigToAVCodecContext( |
545 const VideoDecoderConfig& config, | 566 const VideoDecoderConfig& config, |
546 AVCodecContext* codec_context) { | 567 AVCodecContext* codec_context) { |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 return COLOR_SPACE_HD_REC709; | 747 return COLOR_SPACE_HD_REC709; |
727 case AVCOL_SPC_SMPTE170M: | 748 case AVCOL_SPC_SMPTE170M: |
728 case AVCOL_SPC_BT470BG: | 749 case AVCOL_SPC_BT470BG: |
729 return COLOR_SPACE_SD_REC601; | 750 return COLOR_SPACE_SD_REC601; |
730 default: | 751 default: |
731 DVLOG(1) << "Unknown AVColorSpace: " << color_space; | 752 DVLOG(1) << "Unknown AVColorSpace: " << color_space; |
732 } | 753 } |
733 return COLOR_SPACE_UNSPECIFIED; | 754 return COLOR_SPACE_UNSPECIFIED; |
734 } | 755 } |
735 | 756 |
736 bool FFmpegUTCDateToTime(const char* date_utc, base::Time* out) { | |
737 DCHECK(date_utc); | |
738 DCHECK(out); | |
739 | |
740 std::vector<base::StringPiece> fields = base::SplitStringPiece( | |
741 date_utc, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
742 if (fields.size() != 2) | |
743 return false; | |
744 | |
745 std::vector<base::StringPiece> date_fields = base::SplitStringPiece( | |
746 fields[0], "-", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
747 if (date_fields.size() != 3) | |
748 return false; | |
749 | |
750 // TODO(acolwell): Update this parsing code when FFmpeg returns sub-second | |
751 // information. | |
752 std::vector<base::StringPiece> time_fields = base::SplitStringPiece( | |
753 fields[1], ":", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
754 if (time_fields.size() != 3) | |
755 return false; | |
756 | |
757 base::Time::Exploded exploded; | |
758 exploded.millisecond = 0; | |
759 // This field cannot be uninitialized. Unless not modified, make it 0 here | |
760 // then. | |
761 exploded.day_of_week = 0; | |
762 if (base::StringToInt(date_fields[0], &exploded.year) && | |
763 base::StringToInt(date_fields[1], &exploded.month) && | |
764 base::StringToInt(date_fields[2], &exploded.day_of_month) && | |
765 base::StringToInt(time_fields[0], &exploded.hour) && | |
766 base::StringToInt(time_fields[1], &exploded.minute) && | |
767 base::StringToInt(time_fields[2], &exploded.second)) { | |
768 if (base::Time::FromUTCExploded(exploded, out)) | |
769 return true; | |
770 } | |
771 | |
772 return false; | |
773 } | |
774 | |
775 int32_t HashCodecName(const char* codec_name) { | 757 int32_t HashCodecName(const char* codec_name) { |
776 // Use the first 32-bits from the SHA1 hash as the identifier. | 758 // Use the first 32-bits from the SHA1 hash as the identifier. |
777 int32_t hash; | 759 int32_t hash; |
778 memcpy(&hash, base::SHA1HashString(codec_name).substr(0, 4).c_str(), 4); | 760 memcpy(&hash, base::SHA1HashString(codec_name).substr(0, 4).c_str(), 4); |
779 return hash; | 761 return hash; |
780 } | 762 } |
781 | 763 |
782 #define TEST_PRIMARY(P) \ | 764 #define TEST_PRIMARY(P) \ |
783 static_assert( \ | 765 static_assert( \ |
784 static_cast<int>(gfx::ColorSpace::PrimaryID::P) == AVCOL_PRI_##P, \ | 766 static_cast<int>(gfx::ColorSpace::PrimaryID::P) == AVCOL_PRI_##P, \ |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
831 TEST_COLORSPACE(RESERVED); | 813 TEST_COLORSPACE(RESERVED); |
832 TEST_COLORSPACE(FCC); | 814 TEST_COLORSPACE(FCC); |
833 TEST_COLORSPACE(BT470BG); | 815 TEST_COLORSPACE(BT470BG); |
834 TEST_COLORSPACE(SMPTE170M); | 816 TEST_COLORSPACE(SMPTE170M); |
835 TEST_COLORSPACE(SMPTE240M); | 817 TEST_COLORSPACE(SMPTE240M); |
836 TEST_COLORSPACE(YCOCG); | 818 TEST_COLORSPACE(YCOCG); |
837 TEST_COLORSPACE(BT2020_NCL); | 819 TEST_COLORSPACE(BT2020_NCL); |
838 TEST_COLORSPACE(BT2020_CL); | 820 TEST_COLORSPACE(BT2020_CL); |
839 | 821 |
840 } // namespace media | 822 } // namespace media |
OLD | NEW |