VirtualBox

source: vbox/trunk/src/VBox/Main/include/RecordingInternals.h@ 96175

Last change on this file since 96175 was 96175, checked in by vboxsync, 3 years ago

Recording: Implemented support for Vorbis codec (provided by libvorbis, not enabled by default yet). This also makes all the codec handling more abstract by using a simple codec wrapper, to keep other places free from codec-specific as much as possible. Initial implementation works and output files are being recognized by media players, but there still are some timing bugs to resolve, as well as optimizing the performance. bugref:10275

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.5 KB
Line 
1/* $Id: RecordingInternals.h 96175 2022-08-12 14:01:17Z vboxsync $ */
2/** @file
3 * Recording internals header.
4 */
5
6/*
7 * Copyright (C) 2012-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef MAIN_INCLUDED_RecordingInternals_h
19#define MAIN_INCLUDED_RecordingInternals_h
20#ifndef RT_WITHOUT_PRAGMA_ONCE
21# pragma once
22#endif
23
24#include <list>
25
26#include <iprt/assert.h>
27#include <iprt/types.h> /* drag in stdint.h before vpx does it. */
28
29#include "VBox/com/VirtualBox.h"
30#include "VBox/settings.h"
31#include <VBox/vmm/pdmaudioifs.h>
32
33#ifdef VBOX_WITH_LIBVPX
34# define VPX_CODEC_DISABLE_COMPAT 1
35# include "vpx/vp8cx.h"
36# include "vpx/vpx_image.h"
37# include "vpx/vpx_encoder.h"
38#endif /* VBOX_WITH_LIBVPX */
39
40#ifdef VBOX_WITH_LIBOPUS
41# include <opus.h>
42#endif
43
44#ifdef VBOX_WITH_LIBVORBIS
45# include "vorbis/vorbisenc.h"
46#endif
47
48
49/*********************************************************************************************************************************
50* Defines *
51*********************************************************************************************************************************/
52#define VBOX_RECORDING_OPUS_HZ_MAX 48000 /**< Maximum sample rate (in Hz) Opus can handle. */
53#define VBOX_RECORDING_OPUS_FRAME_MS_DEFAULT 20 /**< Default Opus frame size (in ms). */
54
55#define VBOX_RECORDING_VORBIS_HZ_MAX 48000 /**< Maximum sample rate (in Hz) Vorbis can handle. */
56#define VBOX_RECORDING_VORBIS_FRAME_MS_DEFAULT 20 /**< Default Vorbis frame size (in ms). */
57
58
59/*********************************************************************************************************************************
60* Prototypes *
61*********************************************************************************************************************************/
62struct RECORDINGCODEC;
63typedef RECORDINGCODEC *PRECORDINGCODEC;
64
65struct RECORDINGFRAME;
66typedef RECORDINGFRAME *PRECORDINGFRAME;
67
68
69/*********************************************************************************************************************************
70* Internal structures, defines and APIs *
71*********************************************************************************************************************************/
72
73/**
74 * Enumeration for specifying a (generic) codec type.
75 */
76typedef enum RECORDINGCODECTYPE
77{
78 /** Invalid codec type. Do not use. */
79 RECORDINGCODECTYPE_INVALID = 0,
80 /** Video codec. */
81 RECORDINGCODECTYPE_VIDEO,
82 /** Audio codec. */
83 RECORDINGCODECTYPE_AUDIO
84} RECORDINGCODECTYPE;
85
86/**
87 * Structure for keeping a codec operations table.
88 */
89typedef struct RECORDINGCODECOPS
90{
91 /**
92 * Initializes a codec.
93 *
94 * @returns VBox status code.
95 * @param pCodec Codec instance to initialize.
96 */
97 DECLCALLBACKMEMBER(int, pfnInit, (PRECORDINGCODEC pCodec));
98
99 /**
100 * Destroys a codec.
101 *
102 * @returns VBox status code.
103 * @param pCodec Codec instance to destroy.
104 */
105 DECLCALLBACKMEMBER(int, pfnDestroy, (PRECORDINGCODEC pCodec));
106
107 /**
108 * Parses an options string to configure advanced / hidden / experimental features of a recording stream.
109 * Unknown values will be skipped. Optional.
110 *
111 * @returns VBox status code.
112 * @param pCodec Codec instance to parse options for.
113 * @param strOptions Options string to parse.
114 */
115 DECLCALLBACKMEMBER(int, pfnParseOptions, (PRECORDINGCODEC pCodec, const Utf8Str &strOptions));
116
117 /**
118 * Feeds the codec encoder with data to encode.
119 *
120 * @returns VBox status code.
121 * @param pCodec Codec instance to use.
122 * @param pFrame Pointer to frame data to encode.
123 * @param pvDst Where to store the encoded data on success.
124 * @param cbDst Size (in bytes) of \a pvDst.
125 * @param pcEncoded Where to return the number of encoded blocks in \a pvDst on success. Optional.
126 * @param pcbEncoded Where to return the number of encoded bytes in \a pvDst on success. Optional.
127 */
128 DECLCALLBACKMEMBER(int, pfnEncode, (PRECORDINGCODEC pCodec, const PRECORDINGFRAME pFrame, void *pvDst, size_t cbDst, size_t *pcEncoded, size_t *pcbEncoded));
129
130 /**
131 * Tells the codec to finalize the current stream. Optional.
132 *
133 * @returns VBox status code.
134 * @param pCodec Codec instance to finalize stream for.
135 */
136 DECLCALLBACKMEMBER(int, pfnFinalize, (PRECORDINGCODEC pCodec));
137} RECORDINGCODECOPS, *PRECORDINGCODECOPS;
138
139/**
140 * Structure for keeping a codec callback table.
141 */
142typedef struct RECORDINGCODECCALLBACKS
143{
144 DECLCALLBACKMEMBER(int, pfnWriteData, (PRECORDINGCODEC pCodec, const void *pvData, size_t cbData, void *pvUser));
145 /** User-supplied data pointer. */
146 void *pvUser;
147} RECORDINGCODECCALLBACKS, *PRECORDINGCODECCALLBACKS;
148
149/**
150 * Structure for keeping generic codec parameters.
151 */
152typedef struct RECORDINGCODECPARMS
153{
154 /** The generic codec type. */
155 RECORDINGCODECTYPE enmType;
156 /** The specific codec type, based on \a enmType. */
157 union
158 {
159 /** The container's video codec to use. */
160 RecordingVideoCodec_T enmVideoCodec;
161 /** The container's audio codec to use. */
162 RecordingAudioCodec_T enmAudioCodec;
163 };
164 union
165 {
166 struct
167 {
168 /** Frames per second. */
169 uint8_t uFPS;
170 /** Target width (in pixels) of encoded video image. */
171 uint16_t uWidth;
172 /** Target height (in pixels) of encoded video image. */
173 uint16_t uHeight;
174 /** Minimal delay (in ms) between two video frames.
175 * This value is based on the configured FPS rate. */
176 uint32_t uDelayMs;
177 } Video;
178 struct
179 {
180 /** The codec's used PCM properties. */
181 PDMAUDIOPCMPROPS PCMProps;
182 } Audio;
183 };
184 /** Desired (average) bitrate (in kbps) to use, for codecs which support bitrate management.
185 * Set to 0 to use a variable bit rate (VBR) (if available, otherwise fall back to CBR). */
186 uint32_t uBitrate;
187 /** Time (in ms) an (encoded) frame takes.
188 *
189 * For Opus, valid frame sizes are:
190 * ms Frame size
191 * 2.5 120
192 * 5 240
193 * 10 480
194 * 20 (Default) 960
195 * 40 1920
196 * 60 2880
197 */
198 uint32_t msFrame;
199 /** The frame size in bytes (based on msFrame). */
200 uint32_t cbFrame;
201 /** The frame size in samples per frame (based on msFrame). */
202 uint32_t csFrame;
203} RECORDINGCODECPARMS, *PRECORDINGCODECPARMS;
204
205#ifdef VBOX_WITH_LIBVPX
206/**
207 * VPX encoder state (needs libvpx).
208 */
209typedef struct RECORDINGCODECVPX
210{
211 /** VPX codec context. */
212 vpx_codec_ctx_t Ctx;
213 /** VPX codec configuration. */
214 vpx_codec_enc_cfg_t Cfg;
215 /** VPX image context. */
216 vpx_image_t RawImage;
217 /** Pointer to the codec's internal YUV buffer. */
218 uint8_t *pu8YuvBuf;
219 /** The encoder's deadline (in ms).
220 * The more time the encoder is allowed to spend encoding, the better the encoded
221 * result, in exchange for higher CPU usage and time spent encoding. */
222 unsigned int uEncoderDeadline;
223} RECORDINGCODECVPX;
224/** Pointer to a VPX encoder state. */
225typedef RECORDINGCODECVPX *PRECORDINGCODECVPX;
226#endif /* VBOX_WITH_LIBVPX */
227
228#ifdef VBOX_WITH_LIBOPUS
229/**
230 * Opus encoder state (needs libvorbis).
231 */
232typedef struct RECORDINGCODECOPUS
233{
234 /** Encoder we're going to use. */
235 OpusEncoder *pEnc;
236} RECORDINGCODECOPUS;
237/** Pointer to an Opus encoder state. */
238typedef RECORDINGCODECOPUS *PRECORDINGCODECOPUS;
239#endif /* VBOX_WITH_LIBOPUS */
240
241#ifdef VBOX_WITH_LIBVORBIS
242/**
243 * Vorbis encoder state (needs libvorbis + libogg).
244 */
245typedef struct RECORDINGCODECVORBIS
246{
247 /** Basic information about the audio in a Vorbis bitstream. */
248 vorbis_info info;
249 /** Encoder state. */
250 vorbis_dsp_state dsp_state;
251 /** Current block being worked on. */
252 vorbis_block block_cur;
253} RECORDINGCODECVORBIS;
254/** Pointer to a Vorbis encoder state. */
255typedef RECORDINGCODECVORBIS *PRECORDINGCODECVORBIS;
256#endif /* VBOX_WITH_LIBVORBIS */
257
258/**
259 * Structure for keeping codec-specific data.
260 */
261typedef struct RECORDINGCODEC
262{
263 /** Callback table for codec operations. */
264 RECORDINGCODECOPS Ops;
265 /** Table for user-supplied callbacks. */
266 RECORDINGCODECCALLBACKS Callbacks;
267 /** Generic codec parameters. */
268 RECORDINGCODECPARMS Parms;
269
270#ifdef VBOX_WITH_LIBVPX
271 union
272 {
273 RECORDINGCODECVPX VPX;
274 } Video;
275#endif
276
277#ifdef VBOX_WITH_AUDIO_RECORDING
278 union
279 {
280# ifdef VBOX_WITH_LIBOPUS
281 RECORDINGCODECOPUS Opus;
282# endif /* VBOX_WITH_LIBOPUS */
283# ifdef VBOX_WITH_LIBVORBIS
284 RECORDINGCODECVORBIS Vorbis;
285# endif /* VBOX_WITH_LIBVORBIS */
286 } Audio;
287#endif /* VBOX_WITH_AUDIO_RECORDING */
288
289 /** Timestamp (in ms) of the last frame was encoded. */
290 uint64_t uLastTimeStampMs;
291
292#ifdef VBOX_WITH_STATISTICS /** @todo Register these values with STAM. */
293 struct
294 {
295 /** Number of encoding errors. */
296 uint64_t cEncErrors;
297 /** Number of frames encoded. */
298 uint64_t cEncBlocks;
299 /** Total time (in ms) of already encoded audio data. */
300 uint64_t msEncTotal;
301 } Stats;
302#endif
303} RECORDINGCODEC, *PRECORDINGCODEC;
304
305/**
306 * Enumeration for supported pixel formats.
307 */
308enum RECORDINGPIXELFMT
309{
310 /** Unknown pixel format. */
311 RECORDINGPIXELFMT_UNKNOWN = 0,
312 /** RGB 24. */
313 RECORDINGPIXELFMT_RGB24 = 1,
314 /** RGB 24. */
315 RECORDINGPIXELFMT_RGB32 = 2,
316 /** RGB 565. */
317 RECORDINGPIXELFMT_RGB565 = 3,
318 /** The usual 32-bit hack. */
319 RECORDINGPIXELFMT_32BIT_HACK = 0x7fffffff
320};
321
322/**
323 * Structure for keeping a single recording video frame.
324 */
325typedef struct RECORDINGVIDEOFRAME
326{
327 /** X resolution of this frame. */
328 uint32_t uWidth;
329 /** Y resolution of this frame. */
330 uint32_t uHeight;
331 /** Pixel format of this frame. */
332 uint32_t uPixelFormat;
333 /** RGB buffer containing the unmodified frame buffer data from Main's display. */
334 uint8_t *pu8RGBBuf;
335 /** Size (in bytes) of the RGB buffer. */
336 size_t cbRGBBuf;
337} RECORDINGVIDEOFRAME, *PRECORDINGVIDEOFRAME;
338
339#ifdef VBOX_WITH_AUDIO_RECORDING
340/**
341 * Structure for keeping a single recording audio frame.
342 */
343typedef struct RECORDINGAUDIOFRAME
344{
345 /** Pointer to audio data. */
346 uint8_t *pvBuf;
347 /** Size (in bytes) of audio data. */
348 size_t cbBuf;
349} RECORDINGAUDIOFRAME, *PRECORDINGAUDIOFRAME;
350#endif /* VBOX_WITH_AUDIO_RECORDING */
351
352/**
353 * Structure for keeping a single recording audio frame.
354 */
355typedef struct RECORDINGFRAME
356{
357 uint64_t msTimestamp;
358 union
359 {
360#ifdef VBOX_WITH_AUDIO_RECORDING
361 RECORDINGAUDIOFRAME Audio;
362#endif
363 RECORDINGVIDEOFRAME Video;
364 RECORDINGVIDEOFRAME *VideoPtr;
365 };
366} RECORDINGFRAME, *PRECORDINGFRAME;
367
368/**
369 * Enumeration for specifying a video recording block type.
370 */
371typedef enum RECORDINGBLOCKTYPE
372{
373 /** Uknown block type, do not use. */
374 RECORDINGBLOCKTYPE_UNKNOWN = 0,
375 /** The block is a video frame. */
376 RECORDINGBLOCKTYPE_VIDEO,
377#ifdef VBOX_WITH_AUDIO_RECORDING
378 /** The block is an audio frame. */
379 RECORDINGBLOCKTYPE_AUDIO
380#endif
381} RECORDINGBLOCKTYPE;
382
383#ifdef VBOX_WITH_AUDIO_RECORDING
384void RecordingAudioFrameFree(PRECORDINGAUDIOFRAME pFrame);
385#endif
386void RecordingVideoFrameFree(PRECORDINGVIDEOFRAME pFrame);
387
388/**
389 * Generic structure for keeping a single video recording (data) block.
390 */
391struct RecordingBlock
392{
393 RecordingBlock()
394 : enmType(RECORDINGBLOCKTYPE_UNKNOWN)
395 , cRefs(0)
396 , pvData(NULL)
397 , cbData(0) { }
398
399 virtual ~RecordingBlock()
400 {
401 Reset();
402 }
403
404 void Reset(void)
405 {
406 switch (enmType)
407 {
408 case RECORDINGBLOCKTYPE_UNKNOWN:
409 break;
410
411 case RECORDINGBLOCKTYPE_VIDEO:
412 RecordingVideoFrameFree((PRECORDINGVIDEOFRAME)pvData);
413 break;
414
415#ifdef VBOX_WITH_AUDIO_RECORDING
416 case RECORDINGBLOCKTYPE_AUDIO:
417 RecordingAudioFrameFree((PRECORDINGAUDIOFRAME)pvData);
418 break;
419#endif
420 default:
421 AssertFailed();
422 break;
423 }
424
425 enmType = RECORDINGBLOCKTYPE_UNKNOWN;
426 cRefs = 0;
427 pvData = NULL;
428 cbData = 0;
429 }
430
431 /** The block's type. */
432 RECORDINGBLOCKTYPE enmType;
433 /** Number of references held of this block. */
434 uint16_t cRefs;
435 /** The (absolute) timestamp (in ms, PTS) of this block. */
436 uint64_t msTimestamp;
437 /** Opaque data block to the actual block data, depending on the block's type. */
438 void *pvData;
439 /** Size (in bytes) of the (opaque) data block. */
440 size_t cbData;
441};
442
443/** List for keeping video recording (data) blocks. */
444typedef std::list<RecordingBlock *> RecordingBlockList;
445
446#ifdef VBOX_WITH_AUDIO_RECORDING
447int recordingCodecCreateAudio(PRECORDINGCODEC pCodec, RecordingAudioCodec_T enmAudioCodec);
448#endif
449int recordingCodecCreateVideo(PRECORDINGCODEC pCodec, RecordingVideoCodec_T enmVideoCodec);
450int recordingCodecInit(const PRECORDINGCODEC pCodec, const PRECORDINGCODECCALLBACKS pCallbacks, const settings::RecordingScreenSettings &Settings);
451int recordingCodecDestroy(PRECORDINGCODEC pCodec);
452int recordingCodecEncode(PRECORDINGCODEC pCodec, const PRECORDINGFRAME pFrame, void *pvDst, size_t cbDst, size_t *pcEncoded, size_t *pcbEncoded);
453int recordingCodecFinalize(PRECORDINGCODEC pCodec);
454#endif /* !MAIN_INCLUDED_RecordingInternals_h */
455
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette