Difference between revisions of "GRC services"

From Nintendo Switch Brew
Jump to navigation Jump to search
 
(36 intermediate revisions by 3 users not shown)
Line 8: Line 8:
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Cmd || Name || Notes
+
! Cmd || Name
 +
|-
 +
| 1 || [[#OpenContinuousRecorder]]
 +
|-
 +
| 2 || [[#OpenGameMovieTrimmer]]
 
|-
 
|-
| 1 || OpenContinuousRecorder || Takes a total of 0x28-bytes of input and a handle, returns an [[#IContinuousRecorder]].
+
| 3 || [5.0.0+] [[#OpenOffscreenRecorder]]
 
|-
 
|-
| 2 || OpenGameMovieTrimmer || Takes a total of 0x8-bytes of input and a handle, returns an [[#IGameMovieTrimmer]].
+
| 10 || [18.0.0+]  
 
|-
 
|-
| 3 || [5.0.0+] || Takes a total of 0x8-bytes of input and a handle, returns an [[#IOffscreenRecorder]].
+
| 101 || [5.0.0+] [[#CreateMovieMaker]]
 
|-
 
|-
| 101 || [5.0.0+] || Takes a total of 0x10-bytes of input, returns an [[#IMovieMaker]].
+
| 110 || [19.0.0+]
 
|-
 
|-
| 9903 || [5.0.0+] || Takes 8-bytes of input, no output.
+
| 9903 || [5.0.0+] [[#SetOffscreenRecordingMarker]]
 
|}
 
|}
  
[5.0.0+] OpenContinuousRecorder now takes an additional 0x20-bytes of input.
+
== OpenContinuousRecorder ==
 +
Takes a total of 0x28-bytes of input and a TransferMemory handle, returns an [[#IContinuousRecorder]].
 +
 
 +
[5.0.0+] Now takes an additional 0x20-bytes of input.
 +
 
 +
[15.0.0+] Now only takes 0x20-bytes of input.
 +
 
 +
[18.0.0+] Now takes a total of 0x28 bytes of input.
 +
 
 +
== OpenGameMovieTrimmer ==
 +
Takes an input u64 and a TransferMemory handle, returns an [[#IGameMovieTrimmer]].
 +
 
 +
== OpenOffscreenRecorder ==
 +
Takes a total of 0x8-bytes of input and a TransferMemory handle, returns an [[#IOffscreenRecorder]].
 +
 
 +
== CreateMovieMaker ==
 +
Takes a total of 0x10-bytes of input, returns an [[#IMovieMaker]].
 +
 
 +
== Cmd110 ==
 +
Takes a total of 0x20-bytes of input and a handle. Returns an [[#IMovieWriter]].
 +
 
 +
This is stubbed on NX: this just closes the input handle if needed, then returns Result 0xFFED4.
 +
 
 +
== SetOffscreenRecordingMarker ==
 +
Takes an u64 '''marker''' (value from 0 to 14), no output.
 +
 
 +
Affects the behavior of [[#CompleteOffscreenRecordingFinish]], [[#CompleteOffscreenRecordingFinishEx0]] and [[#CompleteOffscreenRecordingFinishEx1]], forcing them to stop at different stages.
  
 
== IContinuousRecorder ==
 
== IContinuousRecorder ==
Line 30: Line 60:
 
! Cmd || Name
 
! Cmd || Name
 
|-
 
|-
| 1 ||
+
| 1 || StartRecording
 
|-
 
|-
| 2 ||
+
| 2 || StopRecording
 
|-
 
|-
| 10 ||
+
| 4 || [17.0.0+] UpdateRecordingStartTick
 
|-
 
|-
| 11 ||
+
| 10 || GetNotFlushingEvent
 
|-
 
|-
| 12 ||
+
| 11 || StartFlush
 
|-
 
|-
| 13 ||
+
| 12 || CancelFlush
 
|-
 
|-
| 14 || [5.0.0+]
+
| 13 || ResetFlushTime
 +
|-
 +
| 14 || [5.0.0+] StartFlushWithEvent
 
|}
 
|}
  
[5.0.0+] Cmd11 now takes a total of 0x40-bytes of input.
+
[5.0.0+] StartFlush now takes in a ContinuousRecordingFlushParameter (0x40 bytes).
  
[8.0.0+] Cmd11/cmd14 no longer take any rawdata input, these now take a type-0x15 input buffer.
+
[8.0.0+] ContinuousRecordingFlushParameter is now an sf::LargeData type, so StartFlush/StartFlushWithEvent now take in parameter via type-0x15 input buffer.
  
 
== IGameMovieTrimmer ==
 
== IGameMovieTrimmer ==
Line 56: Line 88:
 
! Cmd || Name
 
! Cmd || Name
 
|-
 
|-
| 1 || BeginTrim
+
| 1 || [[#BeginTrim]]
 
|-
 
|-
| 2 || EndTrim
+
| 2 || [[#EndTrim]]
 
|-
 
|-
| 10 || GetNotTrimmingEvent
+
| 10 || [[#GetNotTrimmingEvent]]
 
|-
 
|-
| 20 || SetThumbnailRgba
+
| 20 || [[#SetThumbnailRgba]]
 +
|-
 +
| 21 || [19.0.0+]
 
|}
 
|}
 +
 +
Album uses [[Applet_Manager_services#CreateGameMovieTrimmer|CreateGameMovieTrimmer]], and retries using the cmd in a loop on error 0x8D4 with svcSleepThread(100000000) being used first. Then all 4 of these commands are used in that same func: [[#SetThumbnailRgba]] if the input buffer is set, [[#GetNotTrimmingEvent]], [[#BeginTrim]], waits on the event, then [[#EndTrim]] and cleanup.
 +
 +
=== BeginTrim ===
 +
Takes an input s32 '''start''', a s32 '''end''', and a [[#GameMovieId]], no output.
 +
 +
The two s32s are the start/end timestamps in 0.5s units.
 +
 +
=== EndTrim ===
 +
No input, returns an output [[#GameMovieId]].
 +
 +
This just loads the [[#GameMovieId]] from state, when available.
 +
 +
=== GetNotTrimmingEvent ===
 +
No input, returns an output Event handle with autoclear=false.
 +
 +
=== SetThumbnailRgba ===
 +
Takes a type-0x45 input buffer, a s32 '''width''', and a s32 '''height''', no output.
 +
 +
'''width''' must be 1280, '''height''' must be 720, and the buffer size must be at least 0x384000. After this validation, this just copies the input buffer to state with size 0x384000 and returns 0.
 +
 +
=== Cmd21 ===
 +
Takes a total of 8-bytes of input and a type-0x45 input buffer. No output.
 +
 +
On NX this just Aborts with Result 0xFFED4.
  
 
= grc:d =
 
= grc:d =
 
This is "nn::grcsrv::IRemoteVideoTransfer".
 
This is "nn::grcsrv::IRemoteVideoTransfer".
  
Added with [[6.0.0]].
+
This was added with [[6.0.0]].
 +
 
 +
The max sessions for this service is 4, and it uses 2 IPC handler threads.
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Cmd || Name || Notes
+
! Cmd || Name
 
|-
 
|-
| 1 || || No input/output.
+
| 1 || [[#Initialize]]
 
|-
 
|-
| 2 || || Takes an input u32 (must be value 0-1) and a type-0x6 output buffer, returns a total of 0x10-bytes of output.
+
| 2 || [[#Transfer]]
 +
|-
 +
| 3 || [14.0.0+]
 
|}
 
|}
  
== Cmd1 ==
+
== Initialize ==
Begins video stream. Can only be called once.
+
No input/output.
  
== Cmd2 ==
+
Begins video stream. This must not be used more than once, even from a different service session: otherwise the sysmodule will assert.
Retrieves video data. Takes u32 "stream" (0: video, 1: audio), returns u32 (num_frames?), u32 data_size, u64 (start_timestamp?). Video stream writes H.264 NAL units to the output buffer (try <code>ffplay -f h264</code>). Official code uses buffer size 0x32000 for video, 0x1000 for audio, and multiple threads to read out both streams at the same time.
+
 
 +
== Transfer ==
 +
Takes an u32 '''stream''' (0: video, 1: audio) and a type-0x6 output buffer, returns 2 u32s '''num_frames''' and '''data_size''' and an u64 '''start_timestamp'''.
 +
 
 +
Retrieves stream data from the continuous recorder in use. Video stream writes H.264 NAL units to the output buffer (try <code>ffplay -f h264</code>). Audio stream is PCM16, 2 channels, and sample-rate = 48000Hz. Official code uses buffer size 0x32000 for video, 0x1000 for audio, and multiple threads to read out both streams at the same time.
 +
 
 +
This will block until data is available. This will hang if there is no game title running which has video capture enabled.
  
 
= IOffscreenRecorder =
 
= IOffscreenRecorder =
Line 92: Line 161:
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Cmd || Name || Notes
+
! Cmd || Name
 
|-
 
|-
| 201 || || Takes a total of 0x8-bytes of input, returns a total of 0x8-bytes of output.
+
| 201 || [[#CreateOffscreenLayer]]
 
|-
 
|-
| 202 || || Takes a total of 0x8-bytes of input, no output.
+
| 202 || [[#DestroyOffscreenLayer]]
 
|}
 
|}
 +
 +
== CreateOffscreenLayer ==
 +
Takes an aruid, returns an 8-byte handle to the layer.
 +
 +
== DestroyOffscreenLayer ==
 +
Takes in an 8-byte layer handle previously returned by CreateOffscreenLayer.
  
 
= IMovieMaker =
 
= IMovieMaker =
Line 143: Line 218:
  
 
== SetAlbumShimLibraryVersion ==
 
== SetAlbumShimLibraryVersion ==
Takes a total of 8-bytes of input, no output.
+
Takes an input u64 [[Capture_services#ShimLibraryVersion|ShimLibraryVersion]], no output.
  
 
== OpenOffscreenLayer ==
 
== OpenOffscreenLayer ==
Takes an input u64 '''LayerHandle''', returns an output u32.
+
Takes an input u64 '''LayerHandle''', returns an output s32 '''ID'''.
 +
 
 +
This gets the '''ID''' for the [[#IHOSBinderDriver]] returned by [[#CreateVideoProxy]].
  
 
== CloseOffscreenLayer ==
 
== CloseOffscreenLayer ==
Line 161: Line 238:
 
== RequestOffscreenRecordingFinishReady ==
 
== RequestOffscreenRecordingFinishReady ==
 
Takes an input u64 '''LayerHandle''', no output.
 
Takes an input u64 '''LayerHandle''', no output.
 +
 +
This is the first cmd used by official sw when finishing recording. Then it waits on the Event originally loaded from [[#GetOffscreenLayerRecordingFinishReadyEvent]]. Then CompleteOffscreenRecordingFinishEx* is used, depending on the sdk-nso version. On any errors, [[#AbortOffscreenRecording]] is used.
  
 
== StartOffscreenRecordingEx ==
 
== StartOffscreenRecordingEx ==
Line 169: Line 248:
  
 
Seems to be unused by official user processes, [[#CompleteOffscreenRecordingFinishEx0]] is used instead.
 
Seems to be unused by official user processes, [[#CompleteOffscreenRecordingFinishEx0]] is used instead.
 +
 +
The input buffer contains the optional ApplicationData for the JPEG thumbnail, size must be <=0x400.
 +
 +
The recorded video will not be accessible via the Album-applet since it's stored separately from other Album data.
  
 
== CompleteOffscreenRecordingFinishEx0 ==
 
== CompleteOffscreenRecordingFinishEx0 ==
Takes two input u32s '''width'''/'''height''', an input u64 '''LayerHandle''' and 2 type-0x5 input buffers, no output.
+
Takes two input s32s '''width'''/'''height''', an input u64 '''LayerHandle''' and 2 type-0x5 input buffers, no output.
  
The input buffers are optional, addr=NULL and size=0 can be used for these.
+
The input buffers are optional, addr=NULL and size=0 can be used for these. The first buffer is for [[#CompleteOffscreenRecordingFinish|ApplicationData]], the second buffer buffer contains the RGBA8 image thumbnail.
  
 
'''width'''/'''height''' must be 1280x720, these fields are unused afterwards.
 
'''width'''/'''height''' must be 1280x720, these fields are unused afterwards.
Line 180: Line 263:
  
 
== CompleteOffscreenRecordingFinishEx1 ==
 
== CompleteOffscreenRecordingFinishEx1 ==
Takes two input u32s '''width'''/'''height''', an input u64 '''LayerHandle''' and two type-0x5 input buffers, returns a 0x20-byte output struct.
+
Takes two input s32s '''width'''/'''height''', an input u64 '''LayerHandle''' and two type-0x5 input buffers, returns an output [[Capture_services|ApplicationAlbumEntry]].
  
Same as [[#CompleteOffscreenRecordingFinishEx0]] except the output struct is returned in the cmdreply.
+
Same as [[#CompleteOffscreenRecordingFinishEx0]] except the output struct is returned in the cmdreply. Official sw copies the output struct into a "nn::album::AlbumFileEntry".
 +
 
 +
== GetOffscreenLayerError ==
 +
Takes an input u64 '''LayerHandle''', no output.
  
 
== EncodeOffscreenLayerAudioSample ==
 
== EncodeOffscreenLayerAudioSample ==
Takes an input u64 '''LayerHandle''' and a type-0x5 input buffer, returns an output u64.
+
Takes an input u64 '''LayerHandle''' and a type-0x5 input buffer, returns an output u64 '''out_size'''.
  
== GetOffscreenLayerError ==
+
Official sw enters a loop for handling the user-specified buffer:
Takes an input u64 '''LayerHandle''', no output.
+
* Waits on the Event originally loaded from [[#GetOffscreenLayerAudioEncodeReadyEvent]].
 +
* Uses the cmd with the current buffer_addr+pos and the remaining_size.
 +
* Updates the current pos and remaining_size with the '''out_size'''.
 +
* Repeats the loop until the remaining_size is 0.
  
 
== GetOffscreenLayerRecordingFinishReadyEvent ==
 
== GetOffscreenLayerRecordingFinishReadyEvent ==
Line 195: Line 284:
 
== GetOffscreenLayerAudioEncodeReadyEvent ==
 
== GetOffscreenLayerAudioEncodeReadyEvent ==
 
Takes an input u64 '''LayerHandle''', returns an output event handle with autoclear disabled.
 
Takes an input u64 '''LayerHandle''', returns an output event handle with autoclear disabled.
 +
 +
= IMovieWriter =
 +
This is "nn::grcsrv::IMovieWriter".
 +
 +
This was added with [19.0.0+].
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Cmd || Name
 +
|-
 +
| 0 ||
 +
|-
 +
| 10 ||
 +
|-
 +
| 20 ||
 +
|-
 +
| 100 ||
 +
|-
 +
| 110 ||
 +
|-
 +
| 120 ||
 +
|-
 +
| 130 ||
 +
|}
  
 
= OffscreenRecordingParameter =
 
= OffscreenRecordingParameter =
This is a 0x80-byte struct.
+
This is "nn::grcsrv::OffscreenRecordingParameter".
 +
 
 +
This is a 0x80-byte struct. "nn::grc::OffscreenRecordingParameter" and "nn::album::MovieMakerMovieParameter" are identical to this.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description || Default value
 +
|-
 +
| 0x0 || 0x10 || ? || 0
 +
|-
 +
| 0x10 || 0x4 || Unknown, must match 0x103. || 0x103
 +
|-
 +
| 0x14 || 0x4 || s32 VideoBitRate, 0 is invalid. || 8000000
 +
|-
 +
| 0x18 || 0x4 || s32 VideoWidth, must match 1280 or 1920. || 1280
 +
|-
 +
| 0x1C || 0x4 || s32 VideoHeight, must match 720 or 1080. || 720
 +
|-
 +
| 0x20 || 0x4 || s32 VideoFrameRate, must match 30 or 60. || 30
 +
|-
 +
| 0x24 || 0x4 || s32 VideoKeyFrameInterval, 0 is invalid. || 30
 +
|-
 +
| 0x28 || 0x4 || s32 AudioBitRate || 128000 ([5.0.0-5.1.0] 1536000)
 +
|-
 +
| 0x2C || 0x4 || s32 AudioSampleRate, 0 is invalid. || 48000
 +
|-
 +
| 0x30 || 0x4 || s32 AudioChannelCount, must match 2. || 2
 +
|-
 +
| 0x34 || 0x4 || "nn::audio::SampleFormat" AudioSampleFormat, must match 2. || 2
 +
|-
 +
| 0x38 || 0x4 || "nn::album::ImageOrientation" VideoImageOrientation. || 0
 +
|-
 +
| 0x3C || 0x44 || ? || 0
 +
|}
 +
 
 +
The above default values are initialized by the official user-process via sdk-nso funcs "nn::album::MovieMakerMovieParameter::GetDefaultValue()" / "nn::album::MovieMakerMovieParameter::MovieMakerMovieParameter()" (both funcs are identical).
 +
 
 +
= GameMovieId =
 +
This is "nn::grcsrv::GameMovieId".
 +
 
 +
This is a 0x40-byte struct.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset || Size || Description
 +
|-
 +
| 0x0 || 0x18 || Same as the last 0x18-bytes of [[Capture_services|AlbumEntry]].
 +
|-
 +
| 0x18 || 0x28 || Unused, always zero.
 +
|}
  
 
= IHOSBinderDriver =
 
= IHOSBinderDriver =

Latest revision as of 20:50, 20 November 2024

GRC (Game Recording) uses libstagefright and the NvMMLite TVMR library for writing recorded video to MP4s.

Error reporting is done using the new /dev/nverpt-ctrl ioctls.

grc:c

This is "nn::grcsrv::IGrcService".

Cmd Name
1 #OpenContinuousRecorder
2 #OpenGameMovieTrimmer
3 [5.0.0+] #OpenOffscreenRecorder
10 [18.0.0+]
101 [5.0.0+] #CreateMovieMaker
110 [19.0.0+]
9903 [5.0.0+] #SetOffscreenRecordingMarker

OpenContinuousRecorder

Takes a total of 0x28-bytes of input and a TransferMemory handle, returns an #IContinuousRecorder.

[5.0.0+] Now takes an additional 0x20-bytes of input.

[15.0.0+] Now only takes 0x20-bytes of input.

[18.0.0+] Now takes a total of 0x28 bytes of input.

OpenGameMovieTrimmer

Takes an input u64 and a TransferMemory handle, returns an #IGameMovieTrimmer.

OpenOffscreenRecorder

Takes a total of 0x8-bytes of input and a TransferMemory handle, returns an #IOffscreenRecorder.

CreateMovieMaker

Takes a total of 0x10-bytes of input, returns an #IMovieMaker.

Cmd110

Takes a total of 0x20-bytes of input and a handle. Returns an #IMovieWriter.

This is stubbed on NX: this just closes the input handle if needed, then returns Result 0xFFED4.

SetOffscreenRecordingMarker

Takes an u64 marker (value from 0 to 14), no output.

Affects the behavior of #CompleteOffscreenRecordingFinish, #CompleteOffscreenRecordingFinishEx0 and #CompleteOffscreenRecordingFinishEx1, forcing them to stop at different stages.

IContinuousRecorder

This is "nn::grcsrv::IContinuousRecorder".

Cmd Name
1 StartRecording
2 StopRecording
4 [17.0.0+] UpdateRecordingStartTick
10 GetNotFlushingEvent
11 StartFlush
12 CancelFlush
13 ResetFlushTime
14 [5.0.0+] StartFlushWithEvent

[5.0.0+] StartFlush now takes in a ContinuousRecordingFlushParameter (0x40 bytes).

[8.0.0+] ContinuousRecordingFlushParameter is now an sf::LargeData type, so StartFlush/StartFlushWithEvent now take in parameter via type-0x15 input buffer.

IGameMovieTrimmer

This is "nn::grcsrv::IGameMovieTrimmer".

Cmd Name
1 #BeginTrim
2 #EndTrim
10 #GetNotTrimmingEvent
20 #SetThumbnailRgba
21 [19.0.0+]

Album uses CreateGameMovieTrimmer, and retries using the cmd in a loop on error 0x8D4 with svcSleepThread(100000000) being used first. Then all 4 of these commands are used in that same func: #SetThumbnailRgba if the input buffer is set, #GetNotTrimmingEvent, #BeginTrim, waits on the event, then #EndTrim and cleanup.

BeginTrim

Takes an input s32 start, a s32 end, and a #GameMovieId, no output.

The two s32s are the start/end timestamps in 0.5s units.

EndTrim

No input, returns an output #GameMovieId.

This just loads the #GameMovieId from state, when available.

GetNotTrimmingEvent

No input, returns an output Event handle with autoclear=false.

SetThumbnailRgba

Takes a type-0x45 input buffer, a s32 width, and a s32 height, no output.

width must be 1280, height must be 720, and the buffer size must be at least 0x384000. After this validation, this just copies the input buffer to state with size 0x384000 and returns 0.

Cmd21

Takes a total of 8-bytes of input and a type-0x45 input buffer. No output.

On NX this just Aborts with Result 0xFFED4.

grc:d

This is "nn::grcsrv::IRemoteVideoTransfer".

This was added with 6.0.0.

The max sessions for this service is 4, and it uses 2 IPC handler threads.

Cmd Name
1 #Initialize
2 #Transfer
3 [14.0.0+]

Initialize

No input/output.

Begins video stream. This must not be used more than once, even from a different service session: otherwise the sysmodule will assert.

Transfer

Takes an u32 stream (0: video, 1: audio) and a type-0x6 output buffer, returns 2 u32s num_frames and data_size and an u64 start_timestamp.

Retrieves stream data from the continuous recorder in use. Video stream writes H.264 NAL units to the output buffer (try ffplay -f h264). Audio stream is PCM16, 2 channels, and sample-rate = 48000Hz. Official code uses buffer size 0x32000 for video, 0x1000 for audio, and multiple threads to read out both streams at the same time.

This will block until data is available. This will hang if there is no game title running which has video capture enabled.

IOffscreenRecorder

This is "nn::grcsrv::IOffscreenRecorder".

This was added with [5.0.0+].

Cmd Name
201 #CreateOffscreenLayer
202 #DestroyOffscreenLayer

CreateOffscreenLayer

Takes an aruid, returns an 8-byte handle to the layer.

DestroyOffscreenLayer

Takes in an 8-byte layer handle previously returned by CreateOffscreenLayer.

IMovieMaker

This is "nn::grcsrv::IMovieMaker".

This was added with [5.0.0+].

Cmd Name
2 #CreateVideoProxy
9 [7.0.0+] #SetAlbumShimLibraryVersion
10 #OpenOffscreenLayer
11 #CloseOffscreenLayer
20 #StartOffscreenRecording
21 #AbortOffscreenRecording
22 #RequestOffscreenRecordingFinishReady
23 #CompleteOffscreenRecordingFinish
24 #StartOffscreenRecordingEx
25 #CompleteOffscreenRecordingFinishEx0
26 [7.0.0+] #CompleteOffscreenRecordingFinishEx1
30 #GetOffscreenLayerError
41 #EncodeOffscreenLayerAudioSample
50 #GetOffscreenLayerRecordingFinishReadyEvent
52 #GetOffscreenLayerAudioEncodeReadyEvent

CreateVideoProxy

No input, returns an #IHOSBinderDriver.

SetAlbumShimLibraryVersion

Takes an input u64 ShimLibraryVersion, no output.

OpenOffscreenLayer

Takes an input u64 LayerHandle, returns an output s32 ID.

This gets the ID for the #IHOSBinderDriver returned by #CreateVideoProxy.

CloseOffscreenLayer

Takes an input u64 LayerHandle, no output.

StartOffscreenRecording

Takes an input u64, no output.

Seems to be unused by official user processes, #StartOffscreenRecordingEx is used instead.

AbortOffscreenRecording

Takes an input u64 LayerHandle, no output.

RequestOffscreenRecordingFinishReady

Takes an input u64 LayerHandle, no output.

This is the first cmd used by official sw when finishing recording. Then it waits on the Event originally loaded from #GetOffscreenLayerRecordingFinishReadyEvent. Then CompleteOffscreenRecordingFinishEx* is used, depending on the sdk-nso version. On any errors, #AbortOffscreenRecording is used.

StartOffscreenRecordingEx

Takes an input u64 LayerHandle and an #OffscreenRecordingParameter, no output.

CompleteOffscreenRecordingFinish

Takes an input u64 LayerHandle and a type-0x5 input buffer, no output.

Seems to be unused by official user processes, #CompleteOffscreenRecordingFinishEx0 is used instead.

The input buffer contains the optional ApplicationData for the JPEG thumbnail, size must be <=0x400.

The recorded video will not be accessible via the Album-applet since it's stored separately from other Album data.

CompleteOffscreenRecordingFinishEx0

Takes two input s32s width/height, an input u64 LayerHandle and 2 type-0x5 input buffers, no output.

The input buffers are optional, addr=NULL and size=0 can be used for these. The first buffer is for ApplicationData, the second buffer buffer contains the RGBA8 image thumbnail.

width/height must be 1280x720, these fields are unused afterwards.

Besides width/height, this is the same as #CompleteOffscreenRecordingFinish except the second buffer is user-specified instead of addr=NULL/size=0.

CompleteOffscreenRecordingFinishEx1

Takes two input s32s width/height, an input u64 LayerHandle and two type-0x5 input buffers, returns an output ApplicationAlbumEntry.

Same as #CompleteOffscreenRecordingFinishEx0 except the output struct is returned in the cmdreply. Official sw copies the output struct into a "nn::album::AlbumFileEntry".

GetOffscreenLayerError

Takes an input u64 LayerHandle, no output.

EncodeOffscreenLayerAudioSample

Takes an input u64 LayerHandle and a type-0x5 input buffer, returns an output u64 out_size.

Official sw enters a loop for handling the user-specified buffer:

  • Waits on the Event originally loaded from #GetOffscreenLayerAudioEncodeReadyEvent.
  • Uses the cmd with the current buffer_addr+pos and the remaining_size.
  • Updates the current pos and remaining_size with the out_size.
  • Repeats the loop until the remaining_size is 0.

GetOffscreenLayerRecordingFinishReadyEvent

Takes an input u64 LayerHandle, returns an output event handle with autoclear disabled.

GetOffscreenLayerAudioEncodeReadyEvent

Takes an input u64 LayerHandle, returns an output event handle with autoclear disabled.

IMovieWriter

This is "nn::grcsrv::IMovieWriter".

This was added with [19.0.0+].

Cmd Name
0
10
20
100
110
120
130

OffscreenRecordingParameter

This is "nn::grcsrv::OffscreenRecordingParameter".

This is a 0x80-byte struct. "nn::grc::OffscreenRecordingParameter" and "nn::album::MovieMakerMovieParameter" are identical to this.

Offset Size Description Default value
0x0 0x10 ? 0
0x10 0x4 Unknown, must match 0x103. 0x103
0x14 0x4 s32 VideoBitRate, 0 is invalid. 8000000
0x18 0x4 s32 VideoWidth, must match 1280 or 1920. 1280
0x1C 0x4 s32 VideoHeight, must match 720 or 1080. 720
0x20 0x4 s32 VideoFrameRate, must match 30 or 60. 30
0x24 0x4 s32 VideoKeyFrameInterval, 0 is invalid. 30
0x28 0x4 s32 AudioBitRate 128000 ([5.0.0-5.1.0] 1536000)
0x2C 0x4 s32 AudioSampleRate, 0 is invalid. 48000
0x30 0x4 s32 AudioChannelCount, must match 2. 2
0x34 0x4 "nn::audio::SampleFormat" AudioSampleFormat, must match 2. 2
0x38 0x4 "nn::album::ImageOrientation" VideoImageOrientation. 0
0x3C 0x44 ? 0

The above default values are initialized by the official user-process via sdk-nso funcs "nn::album::MovieMakerMovieParameter::GetDefaultValue()" / "nn::album::MovieMakerMovieParameter::MovieMakerMovieParameter()" (both funcs are identical).

GameMovieId

This is "nn::grcsrv::GameMovieId".

This is a 0x40-byte struct.

Offset Size Description
0x0 0x18 Same as the last 0x18-bytes of AlbumEntry.
0x18 0x28 Unused, always zero.

IHOSBinderDriver

This is the same interface as NV IHOSBinderDriver.