RFR: 8273096: Add support for H.265/HEVC to JavaFX Media [v2]
Kevin Rushforth
kcr at openjdk.java.net
Fri Dec 10 22:48:18 UTC 2021
On Tue, 16 Nov 2021 02:24:11 GMT, Alexander Matveev <almatvee at openjdk.org> wrote:
>> - Added support for H.265/HEVC for all 3 platforms.
>> - Support is added only for .mp4 files over FILE/HTTP/HTTPS protocols. HTTP Live Streaming with H.265/HEVC is not supported.
>> - On Windows mfwrapper was introduced which uses Media Foundation APIs to decode HEVC.
>> - 10 and 12-bit HEVC was tested and also supported, however due to graphics pipeline not supporting 10-bit YUV rendering we will use color converter to convert video frame to 8-bit before sending it for rendering.
>> - Resolution upto 4k is supported.
>>
>> Additional runtime dependency requirements:
>> Windows: Windows 10 with HEVC Video Extensions installed.
>> macOS: macOS High Sierra and later
>> Linux: at least libavcodec56 and libswscale5
>>
>> Additional build dependency:
>> Linux: libswscale-dev
>
> Alexander Matveev has updated the pull request incrementally with one additional commit since the last revision:
>
> 8273096: Add support for H.265/HEVC to JavaFX Media [v3]
Overall, this looks good. I left a few questions and comments inline.
modules/javafx.media/src/main/native/gstreamer/plugins/av/videodecoder.c line 525:
> 523: if (decoder->sws_context == NULL || decoder->dest_frame == NULL ||
> 524: decoder->sws_scale_func == NULL)
> 525: return TRUE;
Should this be `return FALSE;`?
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 313:
> 311: default:
> 312: break;
> 313: }
This block is a no-op. Is this intended? (and if so, is it needed?)
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 517:
> 515: do
> 516: {
> 517: hr = decoder->pDecoder->GetOutputAvailableType(0, dwTypeIndex, &pDecoderOutputType);
Do you need to check `SUCCEEDED(hr)` here?
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 571:
> 569: SafeRelease(&pDecoderOutputType);
> 570:
> 571: } while (hr != MF_E_NO_MORE_TYPES && hr != S_OK);
Should this be `FAILED(hr)` instead of `hr != S_OK`? Also, is it guaranteed to get success or `MF_E_NO_MORE_TYPES`? If not, this could lead to an infinite loop.
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 577:
> 575: do
> 576: {
> 577: hr = decoder->pColorConvert->GetOutputAvailableType(0, dwTypeIndex, &pConverterOutputType);
Same questions for this loop as for the previous.
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 684:
> 682: return FALSE;
> 683: }
> 684: else if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
Is it OK that this case will return FALSE always?
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 723:
> 721:
> 722: if (SUCCEEDED(hr))
> 723: hr = pMediaBuffer->Lock(&pBuffer, &cbMaxLength, &cbCurrentLength);
If this succeeds, but later operations fail, it seems possible that Unlock won't be called in some cases. Might this cause a problem?
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 730:
> 728: GstMapInfo info;
> 729:
> 730: if (!gst_buffer_map(pGstBuffer, &info, GST_MAP_WRITE))
Do you need to check for `pGstBuffer == NULL`? My concern is that either `gst_buffer_map` will crash if it is, or else it return NULL and then `gst_buffer_unref` might crash.
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 791:
> 789: return PO_FLUSHING;
> 790:
> 791: HRESULT hr = decoder->pDecoder->GetOutputStatus(&dwFlags);
Do you not need to check `hr` here?
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 811:
> 809: do
> 810: {
> 811: hr = decoder->pDecoder->GetOutputAvailableType(0, dwTypeIndex, &pOutputType);
Same question as earlier loops -- do you need to check `hr` (from previous time through loop) here?
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 963:
> 961: // Ask decoder to produce all remaining data
> 962: if (SUCCEEDED(hr))
> 963: hr = decoder->pDecoder->ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
Does this `hr` need to be checked?
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 1101:
> 1099:
> 1100: // Get array count
> 1101: arrayCount = *(guint8*)bdata;
Should this count be sanity checked?
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 1114:
> 1112: nalUnitsCount = ((guint16)*(guint8*)bdata) << 8;
> 1113: bdata++; in_bytes_count++;
> 1114: nalUnitsCount |= (guint16)*(guint8*)bdata;
Should this count be sanity checked?
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 1123:
> 1121: nalUnitLength = ((guint16)*(guint8*)bdata) << 8;
> 1122: bdata++; in_bytes_count++;
> 1123: nalUnitLength |= (guint16)*(guint8*)bdata;
Same question about count.
modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp line 1346:
> 1344: default:
> 1345: break;
> 1346: }
This is a no-op. Is it intended?
-------------
PR: https://git.openjdk.java.net/jfx/pull/649
More information about the openjfx-dev
mailing list