summaryrefslogtreecommitdiffstats
path: root/src/VBox/Main/include/RecordingInternals.h
blob: a98f1be5b9f53225d33178acfc14b163a4b0f7dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
/* $Id: RecordingInternals.h $ */
/** @file
 * Recording internals header.
 */

/*
 * Copyright (C) 2012-2023 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

#ifndef MAIN_INCLUDED_RecordingInternals_h
#define MAIN_INCLUDED_RecordingInternals_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <list>

#include <iprt/assert.h>
#include <iprt/types.h> /* drag in stdint.h before vpx does it. */

#include "VBox/com/string.h"
#include "VBox/com/VirtualBox.h"
#include "VBox/settings.h"
#include <VBox/vmm/pdmaudioifs.h>

#ifdef VBOX_WITH_LIBVPX
# define VPX_CODEC_DISABLE_COMPAT 1
# include "vpx/vp8cx.h"
# include "vpx/vpx_image.h"
# include "vpx/vpx_encoder.h"
#endif /* VBOX_WITH_LIBVPX */

#ifdef VBOX_WITH_LIBVORBIS
# include "vorbis/vorbisenc.h"
#endif


/*********************************************************************************************************************************
*   Defines                                                                                                                      *
*********************************************************************************************************************************/
#define VBOX_RECORDING_VORBIS_HZ_MAX             48000   /**< Maximum sample rate (in Hz) Vorbis can handle. */
#define VBOX_RECORDING_VORBIS_FRAME_MS_DEFAULT   20      /**< Default Vorbis frame size (in ms). */


/*********************************************************************************************************************************
*   Prototypes                                                                                                                   *
*********************************************************************************************************************************/
struct RECORDINGCODEC;
typedef RECORDINGCODEC *PRECORDINGCODEC;

struct RECORDINGFRAME;
typedef RECORDINGFRAME *PRECORDINGFRAME;


/*********************************************************************************************************************************
*   Internal structures, defines and APIs                                                                                        *
*********************************************************************************************************************************/

/**
 * Enumeration for specifying a (generic) codec type.
 */
typedef enum RECORDINGCODECTYPE
{
    /** Invalid codec type. Do not use. */
    RECORDINGCODECTYPE_INVALID = 0,
    /** Video codec. */
    RECORDINGCODECTYPE_VIDEO,
    /** Audio codec. */
    RECORDINGCODECTYPE_AUDIO
} RECORDINGCODECTYPE;

/**
 * Structure for keeping a codec operations table.
 */
typedef struct RECORDINGCODECOPS
{
    /**
     * Initializes a codec.
     *
     * @returns VBox status code.
     * @param   pCodec              Codec instance to initialize.
     */
    DECLCALLBACKMEMBER(int, pfnInit,         (PRECORDINGCODEC pCodec));

    /**
     * Destroys a codec.
     *
     * @returns VBox status code.
     * @param   pCodec              Codec instance to destroy.
     */
    DECLCALLBACKMEMBER(int, pfnDestroy,      (PRECORDINGCODEC pCodec));

    /**
     * Parses an options string to configure advanced / hidden / experimental features of a recording stream.
     * Unknown values will be skipped. Optional.
     *
     * @returns VBox status code.
     * @param   pCodec              Codec instance to parse options for.
     * @param   strOptions          Options string to parse.
     */
    DECLCALLBACKMEMBER(int, pfnParseOptions, (PRECORDINGCODEC pCodec, const com::Utf8Str &strOptions));

    /**
     * Feeds the codec encoder with data to encode.
     *
     * @returns VBox status code.
     * @param   pCodec              Codec instance to use.
     * @param   pFrame              Pointer to frame data to encode.
     * @param   pcEncoded           Where to return the number of encoded blocks in \a pvDst on success. Optional.
     * @param   pcbEncoded          Where to return the number of encoded bytes in \a pvDst on success. Optional.
     */
    DECLCALLBACKMEMBER(int, pfnEncode,       (PRECORDINGCODEC pCodec, const PRECORDINGFRAME pFrame, size_t *pcEncoded, size_t *pcbEncoded));

    /**
     * Tells the codec to finalize the current stream. Optional.
     *
     * @returns VBox status code.
     * @param   pCodec              Codec instance to finalize stream for.
     */
    DECLCALLBACKMEMBER(int, pfnFinalize,     (PRECORDINGCODEC pCodec));
} RECORDINGCODECOPS, *PRECORDINGCODECOPS;

/** No encoding flags set. */
#define RECORDINGCODEC_ENC_F_NONE               UINT32_C(0)
/** Data block is a key block. */
#define RECORDINGCODEC_ENC_F_BLOCK_IS_KEY       RT_BIT_32(0)
/** Data block is invisible. */
#define RECORDINGCODEC_ENC_F_BLOCK_IS_INVISIBLE RT_BIT_32(1)
/** Encoding flags valid mask. */
#define RECORDINGCODEC_ENC_F_VALID_MASK         0x1

/**
 * Structure for keeping a codec callback table.
 */
typedef struct RECORDINGCODECCALLBACKS
{
    /**
     * Callback for notifying that encoded data has been written.
     *
     * @returns VBox status code.
     * @param   pCodec          Pointer to codec instance which has written the data.
     * @param   pvData          Pointer to written data (encoded).
     * @param   cbData          Size (in bytes) of \a pvData.
     * @param   msAbsPTS        Absolute PTS (in ms) of the written data.
     * @param   uFlags          Encoding flags of type RECORDINGCODEC_ENC_F_XXX.
     * @param   pvUser          User-supplied pointer.
     */
    DECLCALLBACKMEMBER(int, pfnWriteData, (PRECORDINGCODEC pCodec, const void *pvData, size_t cbData, uint64_t msAbsPTS, uint32_t uFlags, void *pvUser));
    /** User-supplied data pointer. */
    void                   *pvUser;
} RECORDINGCODECCALLBACKS, *PRECORDINGCODECCALLBACKS;

/**
 * Structure for keeping generic codec parameters.
 */
typedef struct RECORDINGCODECPARMS
{
    /** The generic codec type. */
    RECORDINGCODECTYPE          enmType;
    /** The specific codec type, based on \a enmType. */
    union
    {
        /** The container's video codec to use. */
        RecordingVideoCodec_T   enmVideoCodec;
        /** The container's audio codec to use. */
        RecordingAudioCodec_T   enmAudioCodec;
    };
    union
    {
        struct
        {
            /** Frames per second. */
            uint8_t             uFPS;
            /** Target width (in pixels) of encoded video image. */
            uint16_t            uWidth;
            /** Target height (in pixels) of encoded video image. */
            uint16_t            uHeight;
            /** Minimal delay (in ms) between two video frames.
             *  This value is based on the configured FPS rate. */
            uint32_t            uDelayMs;
        } Video;
        struct
        {
            /** The codec's used PCM properties. */
            PDMAUDIOPCMPROPS    PCMProps;
        } Audio;
    };
    /** Desired (average) bitrate (in kbps) to use, for codecs which support bitrate management.
     *  Set to 0 to use a variable bit rate (VBR) (if available, otherwise fall back to CBR). */
    uint32_t                    uBitrate;
    /** Time (in ms) the encoder expects us to send data to encode.
     *
     *  For Vorbis, valid frame sizes are powers of two from 64 to 8192 bytes.
     */
    uint32_t                    msFrame;
    /** The frame size in bytes (based on \a msFrame). */
    uint32_t                    cbFrame;
    /** The frame size in samples per frame (based on \a msFrame). */
    uint32_t                    csFrame;
} RECORDINGCODECPARMS, *PRECORDINGCODECPARMS;

#ifdef VBOX_WITH_LIBVPX
/**
 * VPX encoder state (needs libvpx).
 */
typedef struct RECORDINGCODECVPX
{
    /** VPX codec context. */
    vpx_codec_ctx_t     Ctx;
    /** VPX codec configuration. */
    vpx_codec_enc_cfg_t Cfg;
    /** VPX image context. */
    vpx_image_t         RawImage;
    /** Pointer to the codec's internal YUV buffer. */
    uint8_t            *pu8YuvBuf;
    /** The encoder's deadline (in ms).
     *  The more time the encoder is allowed to spend encoding, the better the encoded
     *  result, in exchange for higher CPU usage and time spent encoding. */
    unsigned int        uEncoderDeadline;
} RECORDINGCODECVPX;
/** Pointer to a VPX encoder state. */
typedef RECORDINGCODECVPX *PRECORDINGCODECVPX;
#endif /* VBOX_WITH_LIBVPX */

#ifdef VBOX_WITH_LIBVORBIS
/**
 * Vorbis encoder state (needs libvorbis + libogg).
 */
typedef struct RECORDINGCODECVORBIS
{
    /** Basic information about the audio in a Vorbis bitstream. */
    vorbis_info      info;
    /** Encoder state. */
    vorbis_dsp_state dsp_state;
    /** Current block being worked on. */
    vorbis_block     block_cur;
} RECORDINGCODECVORBIS;
/** Pointer to a Vorbis encoder state. */
typedef RECORDINGCODECVORBIS *PRECORDINGCODECVORBIS;
#endif /* VBOX_WITH_LIBVORBIS */

/**
 * Structure for keeping a codec's internal state.
 */
typedef struct RECORDINGCODECSTATE
{
    /** Timestamp Timestamp (PTS, in ms) of the last frame was encoded. */
    uint64_t            tsLastWrittenMs;
    /** Number of encoding errors. */
    uint64_t            cEncErrors;
} RECORDINGCODECSTATE;
/** Pointer to an internal encoder state. */
typedef RECORDINGCODECSTATE *PRECORDINGCODECSTATE;

/**
 * Structure for keeping codec-specific data.
 */
typedef struct RECORDINGCODEC
{
    /** Callback table for codec operations. */
    RECORDINGCODECOPS           Ops;
    /** Table for user-supplied callbacks. */
    RECORDINGCODECCALLBACKS     Callbacks;
    /** Generic codec parameters. */
    RECORDINGCODECPARMS         Parms;
    /** Generic codec parameters. */
    RECORDINGCODECSTATE         State;

#ifdef VBOX_WITH_LIBVPX
    union
    {
        RECORDINGCODECVPX       VPX;
    } Video;
#endif

#ifdef VBOX_WITH_AUDIO_RECORDING
    union
    {
# ifdef VBOX_WITH_LIBVORBIS
        RECORDINGCODECVORBIS    Vorbis;
# endif /* VBOX_WITH_LIBVORBIS */
    } Audio;
#endif /* VBOX_WITH_AUDIO_RECORDING */

    /** Internal scratch buffer for en-/decoding steps. */
    void               *pvScratch;
    /** Size (in bytes) of \a pvScratch. */
    uint32_t            cbScratch;

#ifdef VBOX_WITH_STATISTICS /** @todo Register these values with STAM. */
    struct
    {
        /** Number of frames encoded. */
        uint64_t        cEncBlocks;
        /** Total time (in ms) of already encoded audio data. */
        uint64_t        msEncTotal;
    } STAM;
#endif
} RECORDINGCODEC, *PRECORDINGCODEC;

/**
 * Enumeration for supported pixel formats.
 */
enum RECORDINGPIXELFMT
{
    /** Unknown pixel format. */
    RECORDINGPIXELFMT_UNKNOWN    = 0,
    /** RGB 24. */
    RECORDINGPIXELFMT_RGB24      = 1,
    /** RGB 24. */
    RECORDINGPIXELFMT_RGB32      = 2,
    /** RGB 565. */
    RECORDINGPIXELFMT_RGB565     = 3,
    /** The usual 32-bit hack. */
    RECORDINGPIXELFMT_32BIT_HACK = 0x7fffffff
};

/**
 * Enumeration for a recording frame type.
 */
enum RECORDINGFRAME_TYPE
{
    /** Invalid frame type; do not use. */
    RECORDINGFRAME_TYPE_INVALID   = 0,
    /** Frame is an audio frame. */
    RECORDINGFRAME_TYPE_AUDIO     = 1,
    /** Frame is an video frame. */
    RECORDINGFRAME_TYPE_VIDEO     = 2,
    /** Frame contains a video frame pointer. */
    RECORDINGFRAME_TYPE_VIDEO_PTR = 3
};

/**
 * Structure for keeping a single recording video frame.
 */
typedef struct RECORDINGVIDEOFRAME
{
    /** X origin  (in pixel) of this frame. */
    uint16_t            uX;
    /** X origin  (in pixel) of this frame. */
    uint16_t            uY;
    /** X resolution (in pixel) of this frame. */
    uint16_t            uWidth;
    /** Y resolution (in pixel)  of this frame. */
    uint16_t            uHeight;
    /** Bits per pixel (BPP). */
    uint8_t             uBPP;
    /** Pixel format of this frame. */
    RECORDINGPIXELFMT   enmPixelFmt;
    /** Bytes per scan line. */
    uint16_t            uBytesPerLine;
    /** RGB buffer containing the unmodified frame buffer data from Main's display. */
    uint8_t            *pu8RGBBuf;
    /** Size (in bytes) of the RGB buffer. */
    size_t              cbRGBBuf;
} RECORDINGVIDEOFRAME, *PRECORDINGVIDEOFRAME;

/**
 * Structure for keeping a single recording audio frame.
 */
typedef struct RECORDINGAUDIOFRAME
{
    /** Pointer to audio data. */
    uint8_t            *pvBuf;
    /** Size (in bytes) of audio data. */
    size_t              cbBuf;
} RECORDINGAUDIOFRAME, *PRECORDINGAUDIOFRAME;

/**
 * Structure for keeping a single recording audio frame.
 */
typedef struct RECORDINGFRAME
{
    /** List node. */
    RTLISTNODE              Node;
    /** Stream index (hint) where this frame should go to.
     *  Specify UINT16_MAX to broadcast to all streams. */
    uint16_t                idStream;
    /** The frame type. */
    RECORDINGFRAME_TYPE     enmType;
    /** Timestamp (PTS, in ms). */
    uint64_t                msTimestamp;
    union
    {
#ifdef VBOX_WITH_AUDIO_RECORDING
        /** Audio frame data. */
        RECORDINGAUDIOFRAME  Audio;
#endif
        /** Video frame data. */
        RECORDINGVIDEOFRAME  Video;
        /** A (weak) pointer to a video frame. */
        RECORDINGVIDEOFRAME *VideoPtr;
    };
} RECORDINGFRAME, *PRECORDINGFRAME;

/**
 * Enumeration for specifying a video recording block type.
 */
typedef enum RECORDINGBLOCKTYPE
{
    /** Uknown block type, do not use. */
    RECORDINGBLOCKTYPE_UNKNOWN = 0,
    /** The block is a video frame. */
    RECORDINGBLOCKTYPE_VIDEO,
    /** The block is an audio frame. */
    RECORDINGBLOCKTYPE_AUDIO
} RECORDINGBLOCKTYPE;

#ifdef VBOX_WITH_AUDIO_RECORDING
int RecordingVideoFrameInit(PRECORDINGVIDEOFRAME pFrame, int w, int h, uint8_t uBPP, RECORDINGPIXELFMT enmPixelFmt);
void RecordingVideoFrameDestroy(PRECORDINGVIDEOFRAME pFrame);
void RecordingAudioFrameFree(PRECORDINGAUDIOFRAME pFrame);
#endif
void RecordingVideoFrameFree(PRECORDINGVIDEOFRAME pFrame);
void RecordingFrameFree(PRECORDINGFRAME pFrame);

/**
 * Generic structure for keeping a single video recording (data) block.
 */
struct RecordingBlock
{
    RecordingBlock()
        : enmType(RECORDINGBLOCKTYPE_UNKNOWN)
        , cRefs(0)
        , uFlags(RECORDINGCODEC_ENC_F_NONE)
        , pvData(NULL)
        , cbData(0) { }

    virtual ~RecordingBlock()
    {
        Reset();
    }

    void Reset(void)
    {
        switch (enmType)
        {
            case RECORDINGBLOCKTYPE_UNKNOWN:
                break;

            case RECORDINGBLOCKTYPE_VIDEO:
                RecordingVideoFrameFree((PRECORDINGVIDEOFRAME)pvData);
                break;

#ifdef VBOX_WITH_AUDIO_RECORDING
            case RECORDINGBLOCKTYPE_AUDIO:
                RecordingAudioFrameFree((PRECORDINGAUDIOFRAME)pvData);
                break;
#endif
            default:
                AssertFailed();
                break;
        }

        enmType = RECORDINGBLOCKTYPE_UNKNOWN;
        cRefs   = 0;
        pvData  = NULL;
        cbData  = 0;
    }

    /** The block's type. */
    RECORDINGBLOCKTYPE enmType;
    /** Number of references held of this block. */
    uint16_t           cRefs;
    /** Block flags of type RECORDINGCODEC_ENC_F_XXX. */
    uint64_t           uFlags;
    /** The (absolute) timestamp (in ms, PTS) of this block. */
    uint64_t           msTimestamp;
    /** Opaque data block to the actual block data, depending on the block's type. */
    void              *pvData;
    /** Size (in bytes) of the (opaque) data block. */
    size_t             cbData;
};

/** List for keeping video recording (data) blocks. */
typedef std::list<RecordingBlock *> RecordingBlockList;

int recordingCodecCreateAudio(PRECORDINGCODEC pCodec, RecordingAudioCodec_T enmAudioCodec);
int recordingCodecCreateVideo(PRECORDINGCODEC pCodec, RecordingVideoCodec_T enmVideoCodec);
int recordingCodecInit(const PRECORDINGCODEC pCodec, const PRECORDINGCODECCALLBACKS pCallbacks, const settings::RecordingScreenSettings &Settings);
int recordingCodecDestroy(PRECORDINGCODEC pCodec);
int recordingCodecEncode(PRECORDINGCODEC pCodec, const PRECORDINGFRAME pFrame, size_t *pcEncoded, size_t *pcbEncoded);
int recordingCodecFinalize(PRECORDINGCODEC pCodec);
bool recordingCodecIsInitialized(const PRECORDINGCODEC pCodec);
uint32_t recordingCodecGetWritable(const PRECORDINGCODEC pCodec, uint64_t msTimestamp);
#endif /* !MAIN_INCLUDED_RecordingInternals_h */