From 2f687cc58aff8ac1682e831ab167c4d5b699839a Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Tue, 30 Apr 2019 18:55:18 -0700 Subject: [PATCH] Don't modify the decode unit in place --- libgamestream/sps.c | 112 +++++++++++++++----------------------------- libgamestream/sps.h | 3 +- src/video/pi.c | 9 ++-- 3 files changed, 45 insertions(+), 79 deletions(-) diff --git a/libgamestream/sps.c b/libgamestream/sps.c index e61c113..4f8dc76 100644 --- a/libgamestream/sps.c +++ b/libgamestream/sps.c @@ -24,95 +24,59 @@ static h264_stream_t* h264_stream; static int initial_width, initial_height; -static int replay_sps; - void gs_sps_init(int width, int height) { h264_stream = h264_new(); initial_width = width; initial_height = height; } -void gs_sps_fix(PDECODE_UNIT decodeUnit, int flags) { - PLENTRY entry = decodeUnit->bufferList; +void gs_sps_fix(PLENTRY sps, int flags, uint8_t* out_buf, uint32_t* out_offset) { const char naluHeader[] = {0x00, 0x00, 0x00, 0x01}; - if (replay_sps == 1) { - PLENTRY replay_entry = (PLENTRY) malloc(sizeof(*replay_entry) + 128); - if (replay_entry == NULL) - return; + read_nal_unit(h264_stream, sps->data+4, sps->length-4); - replay_entry->data = (char *) (entry + 1); - memcpy(replay_entry->data, naluHeader, sizeof(naluHeader)); - h264_stream->sps->profile_idc = H264_PROFILE_HIGH; - replay_entry->length = write_nal_unit(h264_stream, replay_entry->data+4, 124) + 4; - decodeUnit->fullLength += replay_entry->length; + // Some decoders rely on H264 level to decide how many buffers are needed + // Since we only need one frame buffered, we'll set level as low as we can + // for known resolution combinations. Otherwise leave the profile alone (currently 5.0) + if (initial_width == 1280 && initial_height == 720) + h264_stream->sps->level_idc = 32; // Max 5 buffered frames at 1280x720x60 + else if (initial_width = 1920 && initial_height == 1080) + h264_stream->sps->level_idc = 42; // Max 4 buffered frames at 1920x1080x60 - replay_entry->next = entry; - entry = replay_entry; - replay_sps = 2; - } else if ((entry->data[4] & 0x1F) == NAL_UNIT_TYPE_SPS) { - read_nal_unit(h264_stream, entry->data+4, entry->length-4); + // Some decoders requires a reference frame count of 1 to decode successfully. + h264_stream->sps->num_ref_frames = 1; - // Some decoders rely on H264 level to decide how many buffers are needed - // Since we only need one frame buffered, we'll set level as low as we can - // for known resolution combinations. Otherwise leave the profile alone (currently 5.0) - if (initial_width == 1280 && initial_height == 720) - h264_stream->sps->level_idc = 32; // Max 5 buffered frames at 1280x720x60 - else if (initial_width = 1920 && initial_height == 1080) - h264_stream->sps->level_idc = 42; // Max 4 buffered frames at 1920x1080x60 + // GFE 2.5.11 changed the SPS to add additional extensions + // Some devices don't like these so we remove them here. + h264_stream->sps->vui.video_signal_type_present_flag = 0; + h264_stream->sps->vui.chroma_loc_info_present_flag = 0; - // Some decoders requires a reference frame count of 1 to decode successfully. - h264_stream->sps->num_ref_frames = 1; - - // GFE 2.5.11 changed the SPS to add additional extensions - // Some devices don't like these so we remove them here. - h264_stream->sps->vui.video_signal_type_present_flag = 0; - h264_stream->sps->vui.chroma_loc_info_present_flag = 0; - - if ((flags & GS_SPS_BITSTREAM_FIXUP) == GS_SPS_BITSTREAM_FIXUP) { - // The SPS that comes in the current H264 bytestream doesn't set the bitstream_restriction_flag - // or the max_dec_frame_buffering which increases decoding latency on some devices - // log2_max_mv_length_horizontal and log2_max_mv_length_vertical are set to more - // conservite values by GFE 25.11. We'll let those values stand. - if (!h264_stream->sps->vui.bitstream_restriction_flag) { - h264_stream->sps->vui.bitstream_restriction_flag = 1; - h264_stream->sps->vui.motion_vectors_over_pic_boundaries_flag = 1; - h264_stream->sps->vui.max_bits_per_mb_denom = 1; - h264_stream->sps->vui.log2_max_mv_length_horizontal = 16; - h264_stream->sps->vui.log2_max_mv_length_vertical = 16; - h264_stream->sps->vui.num_reorder_frames = 0; - } - - // Some devices throw errors if max_dec_frame_buffering < num_ref_frames - h264_stream->sps->vui.max_dec_frame_buffering = 1; - - // These values are the default for the fields, but they are more aggressive - // than what GFE sends in 2.5.11, but it doesn't seem to cause picture problems. - h264_stream->sps->vui.max_bytes_per_pic_denom = 2; + if ((flags & GS_SPS_BITSTREAM_FIXUP) == GS_SPS_BITSTREAM_FIXUP) { + // The SPS that comes in the current H264 bytestream doesn't set the bitstream_restriction_flag + // or the max_dec_frame_buffering which increases decoding latency on some devices + // log2_max_mv_length_horizontal and log2_max_mv_length_vertical are set to more + // conservite values by GFE 25.11. We'll let those values stand. + if (!h264_stream->sps->vui.bitstream_restriction_flag) { + h264_stream->sps->vui.bitstream_restriction_flag = 1; + h264_stream->sps->vui.motion_vectors_over_pic_boundaries_flag = 1; h264_stream->sps->vui.max_bits_per_mb_denom = 1; - } else // Devices that didn't/couldn't get bitstream restrictions before GFE 2.5.11 will continue to not receive them now - h264_stream->sps->vui.bitstream_restriction_flag = 0; + h264_stream->sps->vui.log2_max_mv_length_horizontal = 16; + h264_stream->sps->vui.log2_max_mv_length_vertical = 16; + h264_stream->sps->vui.num_reorder_frames = 0; + } - if ((flags & GS_SPS_BASELINE_HACK) == GS_SPS_BASELINE_HACK && !replay_sps) - h264_stream->sps->profile_idc = H264_PROFILE_BASELINE; + // Some devices throw errors if max_dec_frame_buffering < num_ref_frames + h264_stream->sps->vui.max_dec_frame_buffering = 1; - PLENTRY sps_entry = (PLENTRY) malloc(sizeof(*sps_entry) + 128); - if (sps_entry == NULL) - return; + // These values are the default for the fields, but they are more aggressive + // than what GFE sends in 2.5.11, but it doesn't seem to cause picture problems. + h264_stream->sps->vui.max_bytes_per_pic_denom = 2; + h264_stream->sps->vui.max_bits_per_mb_denom = 1; + } else // Devices that didn't/couldn't get bitstream restrictions before GFE 2.5.11 will continue to not receive them now + h264_stream->sps->vui.bitstream_restriction_flag = 0; - PLENTRY next = entry->next; - decodeUnit->fullLength -= entry->length; - free(entry); - sps_entry->data = (char*) (sps_entry + 1); - memcpy(sps_entry->data, naluHeader, sizeof(naluHeader)); - sps_entry->length = write_nal_unit(h264_stream, sps_entry->data+4, 124) + 4; - sps_entry->next = next; - entry = sps_entry; - decodeUnit->fullLength += entry->length; - } else if ((entry->data[4] & 0x1F) == NAL_UNIT_TYPE_PPS) { - if ((flags & GS_SPS_BASELINE_HACK) == GS_SPS_BASELINE_HACK && !replay_sps) - replay_sps = 1; + memcpy(out_buf+*out_offset, naluHeader, 4); + *out_offset += 4; - } - decodeUnit->bufferList = entry; + *out_offset = write_nal_unit(h264_stream, out_buf+*out_offset, 128); } diff --git a/libgamestream/sps.h b/libgamestream/sps.h index 6752323..1f4b1b4 100644 --- a/libgamestream/sps.h +++ b/libgamestream/sps.h @@ -20,7 +20,6 @@ #include #define GS_SPS_BITSTREAM_FIXUP 0x01 -#define GS_SPS_BASELINE_HACK 0x02 void gs_sps_init(int width, int height); -void gs_sps_fix(PDECODE_UNIT decodeUnit, int flags); +void gs_sps_fix(PLENTRY sps, int flags, uint8_t* out_buf, uint32_t* out_offset); diff --git a/src/video/pi.c b/src/video/pi.c index 66dcfbc..38bb8f2 100644 --- a/src/video/pi.c +++ b/src/video/pi.c @@ -209,7 +209,6 @@ static void decoder_renderer_cleanup() { static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { OMX_BUFFERHEADERTYPE *buf = NULL; - gs_sps_fix(decodeUnit, GS_SPS_BITSTREAM_FIXUP); PLENTRY entry = decodeUnit->bufferList; while (entry != NULL) { if (buf == NULL) { @@ -226,8 +225,12 @@ static int decoder_renderer_submit_decode_unit(PDECODE_UNIT decodeUnit) { } } - memcpy(buf->pBuffer + buf->nFilledLen, entry->data, entry->length); - buf->nFilledLen += entry->length; + if (entry->bufferType == BUFFER_TYPE_SPS) + gs_sps_fix(entry, GS_SPS_BITSTREAM_FIXUP, buf->pBuffer, &buf->nFilledLen); + else { + memcpy(buf->pBuffer + buf->nFilledLen, entry->data, entry->length); + buf->nFilledLen += entry->length; + } if (entry->bufferType != BUFFER_TYPE_PICDATA || entry->next == NULL || entry->next->bufferType != BUFFER_TYPE_PICDATA) { if(port_settings_changed == 0 && ((buf->nFilledLen > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) || (buf->nFilledLen == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1, ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0))) {