Changeset 278158 in webkit


Ignore:
Timestamp:
May 27, 2021 3:19:17 AM (14 months ago)
Author:
youenn@apple.com
Message:

Support H264 profiles in MediaRecorder
https://bugs.webkit.org/show_bug.cgi?id=226219
<rdar://78027944>

Reviewed by Eric Carlson.

Source/WebCore:

Use mimeType option given in MediaRecorder options to detect which H264 profile to use.
Implement this by parsing the mime type codec parameter and use the avc1.WXYZ string to compute the profile.
By default, use baseline profile, which is not VideoToolbox profile but has wider decoding support.
If profile specified by the application fails, we downgrade to baseline.

Test: http/wpt/mediarecorder/MediaRecorder-video-h264-profiles.html

  • Modules/mediarecorder/MediaRecorderProvider.cpp:

(WebCore::MediaRecorderProvider::isSupported):

  • platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h:
  • platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm:

(WebCore::MediaRecorderPrivateWriter::create):
(WebCore::MediaRecorderPrivateWriter::initialize):
(WebCore::MediaRecorderPrivateWriter::setOptions): Deleted.

  • platform/mediarecorder/cocoa/VideoSampleBufferCompressor.h:
  • platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm:

(WebCore::VideoSampleBufferCompressor::create):
(WebCore::VideoSampleBufferCompressor::VideoSampleBufferCompressor):
(WebCore::VideoSampleBufferCompressor::vtProfileLevel const):
(WebCore::VideoSampleBufferCompressor::initCompressionSession):

LayoutTests:

  • http/wpt/mediarecorder/MediaRecorder-video-h264-profiles-expected.txt: Added.
  • http/wpt/mediarecorder/MediaRecorder-video-h264-profiles.html: Added.
Location:
trunk
Files:
2 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r278155 r278158  
     12021-05-27  Youenn Fablet  <youenn@apple.com>
     2
     3        Support H264 profiles in MediaRecorder
     4        https://bugs.webkit.org/show_bug.cgi?id=226219
     5        <rdar://78027944>
     6
     7        Reviewed by Eric Carlson.
     8
     9        * http/wpt/mediarecorder/MediaRecorder-video-h264-profiles-expected.txt: Added.
     10        * http/wpt/mediarecorder/MediaRecorder-video-h264-profiles.html: Added.
     11
    1122021-05-27  Kimmo Kinnunen  <kkinnunen@apple.com>
    213
  • trunk/Source/WebCore/ChangeLog

    r278154 r278158  
     12021-05-27  Youenn Fablet  <youenn@apple.com>
     2
     3        Support H264 profiles in MediaRecorder
     4        https://bugs.webkit.org/show_bug.cgi?id=226219
     5        <rdar://78027944>
     6
     7        Reviewed by Eric Carlson.
     8
     9        Use mimeType option given in MediaRecorder options to detect which H264 profile to use.
     10        Implement this by parsing the mime type codec parameter and use the avc1.WXYZ string to compute the profile.
     11        By default, use baseline profile, which is not VideoToolbox profile but has wider decoding support.
     12        If profile specified by the application fails, we downgrade to baseline.
     13
     14        Test: http/wpt/mediarecorder/MediaRecorder-video-h264-profiles.html
     15
     16        * Modules/mediarecorder/MediaRecorderProvider.cpp:
     17        (WebCore::MediaRecorderProvider::isSupported):
     18        * platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h:
     19        * platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm:
     20        (WebCore::MediaRecorderPrivateWriter::create):
     21        (WebCore::MediaRecorderPrivateWriter::initialize):
     22        (WebCore::MediaRecorderPrivateWriter::setOptions): Deleted.
     23        * platform/mediarecorder/cocoa/VideoSampleBufferCompressor.h:
     24        * platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm:
     25        (WebCore::VideoSampleBufferCompressor::create):
     26        (WebCore::VideoSampleBufferCompressor::VideoSampleBufferCompressor):
     27        (WebCore::VideoSampleBufferCompressor::vtProfileLevel const):
     28        (WebCore::VideoSampleBufferCompressor::initCompressionSession):
     29
    1302021-05-27  Carlos Garcia Campos  <cgarcia@igalia.com>
    231
  • trunk/Source/WebCore/Modules/mediarecorder/MediaRecorderProvider.cpp

    r267825 r278158  
    5959    for (auto& item : mimeType.codecs()) {
    6060        auto codec = StringView(item).stripLeadingAndTrailingMatchedCharacters(isHTMLSpace<UChar>);
    61         // FIXME: We should further validate paramters.
     61        // FIXME: We should further validate parameters.
    6262        if (!startsWithLettersIgnoringASCIICase(codec, "avc1") && !startsWithLettersIgnoringASCIICase(codec, "mp4a"))
    6363            return false;
  • trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.h

    r277958 r278158  
    8686    void clear();
    8787
    88     bool initialize();
    89     void setOptions(const MediaRecorderPrivateOptions&);
     88    bool initialize(const MediaRecorderPrivateOptions&);
    9089
    9190    static void compressedVideoOutputBufferCallback(void*, CMBufferQueueTriggerToken);
  • trunk/Source/WebCore/platform/mediarecorder/cocoa/MediaRecorderPrivateWriterCocoa.mm

    r277934 r278158  
    9999{
    100100    auto writer = adoptRef(*new MediaRecorderPrivateWriter(hasAudio, hasVideo));
    101     if (!writer->initialize())
     101    if (!writer->initialize(options))
    102102        return nullptr;
    103     writer->setOptions(options);
    104103    return writer;
    105104}
     
    132131}
    133132
    134 bool MediaRecorderPrivateWriter::initialize()
     133bool MediaRecorderPrivateWriter::initialize(const MediaRecorderPrivateOptions& options)
    135134{
    136135    NSError *error = nil;
     
    150149        if (!m_audioCompressor)
    151150            return false;
     151        if (options.audioBitsPerSecond)
     152            m_audioCompressor->setBitsPerSecond(*options.audioBitsPerSecond);
    152153    }
    153154    if (m_hasVideo) {
    154         m_videoCompressor = VideoSampleBufferCompressor::create(kCMVideoCodecType_H264, compressedVideoOutputBufferCallback, this);
     155        m_videoCompressor = VideoSampleBufferCompressor::create(options.mimeType, compressedVideoOutputBufferCallback, this);
    155156        if (!m_videoCompressor)
    156157            return false;
    157     }
     158        if (options.videoBitsPerSecond)
     159            m_videoCompressor->setBitsPerSecond(*options.videoBitsPerSecond);
     160    }
     161
    158162    return true;
    159 }
    160 
    161 void MediaRecorderPrivateWriter::setOptions(const MediaRecorderPrivateOptions& options)
    162 {
    163     if (options.audioBitsPerSecond && m_audioCompressor)
    164         m_audioCompressor->setBitsPerSecond(*options.audioBitsPerSecond);
    165     if (options.videoBitsPerSecond && m_videoCompressor)
    166         m_videoCompressor->setBitsPerSecond(*options.videoBitsPerSecond);
    167163}
    168164
  • trunk/Source/WebCore/platform/mediarecorder/cocoa/VideoSampleBufferCompressor.h

    r274296 r278158  
    3939    WTF_MAKE_FAST_ALLOCATED;
    4040public:
    41     static std::unique_ptr<VideoSampleBufferCompressor> create(CMVideoCodecType, CMBufferQueueTriggerCallback, void* callbackObject);
     41    static std::unique_ptr<VideoSampleBufferCompressor> create(String mimeType, CMBufferQueueTriggerCallback, void* callbackObject);
    4242    ~VideoSampleBufferCompressor();
    4343
     
    5151
    5252private:
    53     explicit VideoSampleBufferCompressor(CMVideoCodecType);
     53    enum class Profile { Baseline, Main, High };
     54    VideoSampleBufferCompressor(CMVideoCodecType, Profile);
    5455
    5556    bool initialize(CMBufferQueueTriggerCallback, void* callbackObject);
     
    5758    void processSampleBuffer(CMSampleBufferRef);
    5859    bool initCompressionSession(CMVideoFormatDescriptionRef);
     60    CFStringRef vtProfileLevel() const;
    5961
    6062    static void videoCompressionCallback(void *refCon, void*, OSStatus, VTEncodeInfoFlags, CMSampleBufferRef);
     
    7072    unsigned m_expectedFrameRate { 30 };
    7173    Optional<unsigned> m_outputBitRate;
     74    Profile m_profile;
    7275};
    7376
  • trunk/Source/WebCore/platform/mediarecorder/cocoa/VideoSampleBufferCompressor.mm

    r274296 r278158  
    2828#if ENABLE(MEDIA_STREAM) && USE(AVFOUNDATION)
    2929
     30#import "ContentType.h"
    3031#import "Logging.h"
    3132#import <CoreMedia/CoreMedia.h>
     
    4041using namespace PAL;
    4142
    42 std::unique_ptr<VideoSampleBufferCompressor> VideoSampleBufferCompressor::create(CMVideoCodecType outputCodecType, CMBufferQueueTriggerCallback callback, void* callbackObject)
    43 {
    44     auto compressor = std::unique_ptr<VideoSampleBufferCompressor>(new VideoSampleBufferCompressor(outputCodecType));
     43std::unique_ptr<VideoSampleBufferCompressor> VideoSampleBufferCompressor::create(String mimeType, CMBufferQueueTriggerCallback callback, void* callbackObject)
     44{
     45    auto profile = Profile::Baseline;
     46    for (auto codec : ContentType(mimeType).codecs()) {
     47        if (startsWithLettersIgnoringASCIICase(codec, "avc1.") && codec.length() >= 11) {
     48            if (codec[5] == '6' && codec[6] == '4')
     49                profile = Profile::High;
     50            else if (codec[5] == '4' && (codec[6] == 'd' || codec[6] == 'D'))
     51                profile = Profile::Main;
     52            break;
     53        }
     54    }
     55
     56    auto compressor = std::unique_ptr<VideoSampleBufferCompressor>(new VideoSampleBufferCompressor(kCMVideoCodecType_H264, profile));
    4557    if (!compressor->initialize(callback, callbackObject))
    4658        return nullptr;
     
    4860}
    4961
    50 VideoSampleBufferCompressor::VideoSampleBufferCompressor(CMVideoCodecType outputCodecType)
     62VideoSampleBufferCompressor::VideoSampleBufferCompressor(CMVideoCodecType outputCodecType, Profile profile)
    5163    : m_serialDispatchQueue { WorkQueue::create("com.apple.VideoSampleBufferCompressor") }
    5264    , m_outputCodecType { outputCodecType }
     65    , m_profile { profile }
    5366{
    5467}
     
    112125    OSStatus status = VTSessionSetProperty(vtSession, key, cfValue.get());
    113126    return status;
     127}
     128
     129CFStringRef VideoSampleBufferCompressor::vtProfileLevel() const
     130{
     131    switch (m_profile) {
     132    case Profile::Baseline:
     133        return kVTProfileLevel_H264_Baseline_AutoLevel;
     134    case Profile::High:
     135        return kVTProfileLevel_H264_High_AutoLevel;
     136    case Profile::Main:
     137        return kVTProfileLevel_H264_Main_AutoLevel;
     138    }
    114139}
    115140
     
    138163    RELEASE_LOG_ERROR_IF(error, MediaStream, "VideoSampleBufferCompressor VTSessionSetProperty kVTCompressionPropertyKey_ExpectedFrameRate failed with %d", error);
    139164
     165    error = VTSessionSetProperty(m_vtSession.get(), kVTCompressionPropertyKey_ProfileLevel, vtProfileLevel());
     166    if (error) {
     167        RELEASE_LOG_ERROR(MediaStream, "VideoSampleBufferCompressor VTSessionSetProperty kVTCompressionPropertyKey_ProfileLevel failed with %d for profile %d", error, m_profile);
     168        if (m_profile != Profile::Baseline) {
     169            error = VTSessionSetProperty(m_vtSession.get(), kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_H264_Baseline_AutoLevel);
     170            RELEASE_LOG_ERROR_IF(error, MediaStream, "VideoSampleBufferCompressor VTSessionSetProperty kVTCompressionPropertyKey_ProfileLevel failed with %d for default profile", error);
     171        }
     172    }
     173
    140174    if (m_outputBitRate) {
    141175        error = setCompressionSessionProperty(m_vtSession.get(), kVTCompressionPropertyKey_AverageBitRate, *m_outputBitRate);
Note: See TracChangeset for help on using the changeset viewer.