VirtualBox

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

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