Line 8: |
Line 8: |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
| |- | | |- |
− | ! Cmd || Name || Notes | + | ! Cmd || Name |
| |- | | |- |
− | | 1 || OpenContinuousRecorder || Takes a total of 0x28-bytes of input and a handle, returns an [[#IContinuousRecorder]]. | + | | 1 || [[#OpenContinuousRecorder]] |
| |- | | |- |
− | | 2 || OpenGameMovieTrimmer || Takes an input u64 and a handle, returns an [[#IGameMovieTrimmer]]. | + | | 2 || [[#OpenGameMovieTrimmer]] |
| |- | | |- |
− | | 3 || [5.0.0+] || Takes a total of 0x8-bytes of input and a handle, returns an [[#IOffscreenRecorder]]. | + | | 3 || [5.0.0+] [[#OpenOffscreenRecorder]] |
| |- | | |- |
− | | 101 || [5.0.0+] || Takes a total of 0x10-bytes of input, returns an [[#IMovieMaker]]. | + | | 101 || [5.0.0+] [[#CreateMovieMaker]] |
| |- | | |- |
− | | 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 handle, returns an [[#IContinuousRecorder]]. |
| + | |
| + | [5.0.0+] Now takes an additional 0x20-bytes of input. |
| + | |
| + | == OpenGameMovieTrimmer == |
| + | Takes an input u64 and a handle, returns an [[#IGameMovieTrimmer]]. |
| + | |
| + | == OpenOffscreenRecorder == |
| + | Takes a total of 0x8-bytes of input and a handle, returns an [[#IOffscreenRecorder]]. |
| + | |
| + | == CreateMovieMaker == |
| + | Takes a total of 0x10-bytes of input, returns an [[#IMovieMaker]]. |
| + | |
| + | == 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 88: |
Line 105: |
| 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]] |
| |} | | |} |
| | | |
− | == 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 163: |
Line 188: |
| | | |
| == 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 181: |
Line 208: |
| == 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 189: |
Line 218: |
| | | |
| 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 200: |
Line 233: |
| | | |
| == 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 217: |
Line 256: |
| | | |
| = 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 = | | = GameMovieId = |
| + | This is "nn::grcsrv::GameMovieId". |
| + | |
| + | This is a 0x40-byte struct. |
| + | |
| {| class="wikitable" border="1" | | {| class="wikitable" border="1" |
| |- | | |- |
Line 228: |
Line 306: |
| | 0x18 || 0x28 || Unused, always zero. | | | 0x18 || 0x28 || Unused, always zero. |
| |} | | |} |
− |
| |
− | This is "nn::grcsrv::GameMovieId". This is a 0x40-byte struct.
| |
| | | |
| = IHOSBinderDriver = | | = IHOSBinderDriver = |