VirtualBox

Ignore:
Timestamp:
Aug 12, 2022 2:01:17 PM (2 years ago)
Author:
vboxsync
Message:

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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/RecordingInternals.h

    r93115 r96175  
    2727#include <iprt/types.h> /* drag in stdint.h before vpx does it. */
    2828
     29#include "VBox/com/VirtualBox.h"
     30#include "VBox/settings.h"
     31#include <VBox/vmm/pdmaudioifs.h>
     32
    2933#ifdef VBOX_WITH_LIBVPX
    3034# define VPX_CODEC_DISABLE_COMPAT 1
     
    3438#endif /* VBOX_WITH_LIBVPX */
    3539
    36 /**
    37  * Structure for keeping specific recording video codec data.
    38  */
    39 typedef struct RECORDINGVIDEOCODEC
    40 {
     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
    41270#ifdef VBOX_WITH_LIBVPX
    42271    union
    43272    {
    44         struct
    45         {
    46             /** VPX codec context. */
    47             vpx_codec_ctx_t     Ctx;
    48             /** VPX codec configuration. */
    49             vpx_codec_enc_cfg_t Cfg;
    50             /** VPX image context. */
    51             vpx_image_t         RawImage;
    52             /** Pointer to the codec's internal YUV buffer. */
    53             uint8_t            *pu8YuvBuf;
    54             /** The encoder's deadline (in ms).
    55              *  The more time the encoder is allowed to spend encoding, the better the encoded
    56              *  result, in exchange for higher CPU usage and time spent encoding. */
    57             unsigned int        uEncoderDeadline;
    58         } VPX;
    59     };
    60 #endif /* VBOX_WITH_LIBVPX */
    61 } RECORDINGVIDEOCODEC, *PRECORDINGVIDEOCODEC;
     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;
    62304
    63305/**
     
    106348    size_t              cbBuf;
    107349} RECORDINGAUDIOFRAME, *PRECORDINGAUDIOFRAME;
    108 #endif
     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;
    109367
    110368/**
     
    186444typedef std::list<RecordingBlock *> RecordingBlockList;
    187445
     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);
    188454#endif /* !MAIN_INCLUDED_RecordingInternals_h */
    189455
Note: See TracChangeset for help on using the changeset viewer.

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