VirtualBox

Changeset 68338 in vbox


Ignore:
Timestamp:
Aug 8, 2017 10:34:58 AM (7 years ago)
Author:
vboxsync
Message:

Audio/VideoRec: Only open one (output) sink per VM and encode into that, be more specific about frame time calculation.

Location:
trunk/src/VBox/Main/src-client
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-client/DrvAudioVideoRec.cpp

    r68323 r68338  
    123123    /** The encoding rate to use. */
    124124    uint32_t                uHz;
    125     /** Duration of the frame in samples (per channel).
    126      *
    127      *  For Opus, valid frame size are:
    128      *  ms           Frame size
    129      *  2.5          120
    130      *  5            240
    131      *  10           480
    132      *  20 (Default) 960
    133      *  40           1920
    134      *  60           2880
    135      */
    136125    /** Number of audio channels to encode.
    137126     *  Currently we only supported stereo (2) channels. */
    138127    uint8_t                 cChannels;
     128    /** Bits per sample. */
     129    uint8_t                 cBits;
    139130    /** The codec's bitrate. 0 if not used / cannot be specified. */
    140131    uint32_t                uBitrate;
     
    156147            /** Encoder we're going to use. */
    157148            OpusEncoder    *pEnc;
    158             /** Number of samples per frame. */
    159             uint32_t        csFrame;
    160             /** The maximum frame size (in samples) we can handle. */
    161             uint32_t        csFrameMax;
     149            /** Time (in ms) an (encoded) frame takes.
     150             *
     151             *  For Opus, valid frame size are:
     152             *  ms           Frame size
     153             *  2.5          120
     154             *  5            240
     155             *  10           480
     156             *  20 (Default) 960
     157             *  40           1920
     158             *  60           2880
     159             */
     160            uint32_t        msFrame;
    162161        } Opus;
    163162#endif /* VBOX_WITH_LIBOPUS */
     
    182181    /** Container data to use for data processing. */
    183182    AVRECCONTAINER       Con;
    184     /** Codec data this stream uses for encoding. */
     183    /** Codec data this sink uses for encoding. */
    185184    AVRECCODEC           Codec;
    186185} AVRECSINK, *PAVRECSINK;
     
    233232static int avRecSinkInit(PDRVAUDIOVIDEOREC pThis, PAVRECSINK pSink, PAVRECCONTAINERPARMS pConParms, PAVRECCODECPARMS pCodecParms)
    234233{
    235     uint32_t uHz = pCodecParms->uHz;
     234    uint32_t uHz       = pCodecParms->uHz;
     235    uint8_t  cBits     = 16; /** @ŧodo Make this configurable? */
     236    uint8_t  cChannels = pCodecParms->cChannels;
     237    uint32_t uBitrate  = pCodecParms->uBitrate;
    236238
    237239    /* Opus only supports certain input sample rates in an efficient manner.
     
    243245    else     uHz = 8000;
    244246
    245     OpusEncoder *pEnc = NULL;
     247    if (cChannels > 2)
     248    {
     249        LogRel(("VideoRec: More than 2 (stereo) channels are not supported at the moment\n"));
     250        cChannels = 2;
     251    }
     252
     253    LogRel2(("VideoRec: Recording audio in %RU16Hz, %RU8 channels, %RU32 bitrate\n", uHz, cChannels, uBitrate));
    246254
    247255    int orc;
    248     pEnc = opus_encoder_create(pCodecParms->uHz, pCodecParms->cChannels, OPUS_APPLICATION_AUDIO, &orc);
     256    OpusEncoder *pEnc = opus_encoder_create(uHz, cChannels, OPUS_APPLICATION_AUDIO, &orc);
    249257    if (orc != OPUS_OK)
    250258    {
     
    255263    AssertPtr(pEnc);
    256264
    257     opus_encoder_ctl(pEnc, OPUS_SET_BITRATE(pCodecParms->uBitrate));
     265    opus_encoder_ctl(pEnc, OPUS_SET_BITRATE(uBitrate));
    258266    if (orc != OPUS_OK)
    259267    {
    260         LogRel(("VideoRec: Audio codec failed to set bitrate (%RU32): %s\n", pCodecParms->uBitrate, opus_strerror(orc)));
     268        opus_encoder_destroy(pEnc);
     269        pEnc = NULL;
     270
     271        LogRel(("VideoRec: Audio codec failed to set bitrate (%RU32): %s\n", uBitrate, opus_strerror(orc)));
    261272        return VERR_AUDIO_BACKEND_INIT_FAILED;
    262273    }
    263 
    264     LogRel(("VideoRec: Recording audio in %RU16Hz, %RU8 channels, %RU32 bpS\n",
    265             pCodecParms->uHz, pCodecParms->cChannels, pCodecParms->uBitrate / 1000));
    266274
    267275    int rc;
     
    281289            case AVRECCONTAINERTYPE_WEBM:
    282290            {
    283                 rc = VINF_SUCCESS;
     291                /* If we only record audio, create our own WebM writer instance here. */
     292                if (!pSink->Con.WebM.pWebM) /* Do we already have our WebM writer instance? */
     293                {
     294                    char szFile[RTPATH_MAX];
     295                    if (RTStrPrintf(szFile, sizeof(szFile), "%s%s",
     296                                    VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH, "DrvAudioVideoRec.webm" /** @todo Make this configurable. */))
     297                    {
     298                        /** @todo Add sink name / number to file name. */
     299
     300                        LogRel2(("VideoRec: Recording audio to file '%s'\n", szFile));
     301
     302                        pSink->Con.WebM.pWebM = new WebMWriter();
     303                        rc = pSink->Con.WebM.pWebM->Create(szFile,
     304                                                           /** @ŧodo Add option to add some suffix if file exists instead of overwriting? */
     305                                                           RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE,
     306                                                           WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_None);
     307                        if (RT_SUCCESS(rc))
     308                        {
     309                            rc = pSink->Con.WebM.pWebM->AddAudioTrack(uHz, cChannels, cBits,
     310                                                                      &pSink->Con.WebM.uTrack);
     311                            if (RT_FAILURE(rc))
     312                                LogRel(("VideoRec: Error creating audio track for file '%s' (%Rrc)\n", szFile, rc));
     313                        }
     314                        else
     315                            LogRel(("VideoRec: Error creating audio file '%s' (%Rrc)\n", szFile, rc));
     316                    }
     317                    else
     318                    {
     319                        AssertFailed(); /* Should never happen. */
     320                        LogRel(("VideoRec: Error creating audio file path\n"));
     321                    }
     322                }
     323
    284324                break;
    285325            }
     
    300340
    301341        pSink->Codec.Parms.uHz       = uHz;
    302         pSink->Codec.Parms.cChannels = pCodecParms->cChannels;
    303         pSink->Codec.Parms.uBitrate  = pCodecParms->uBitrate;
     342        pSink->Codec.Parms.cChannels = cChannels;
     343        pSink->Codec.Parms.cBits     = cBits;
     344        pSink->Codec.Parms.uBitrate  = uBitrate;
    304345
    305346        pSink->Codec.Opus.pEnc       = pEnc;
    306         pSink->Codec.Opus.csFrame    = uHz / 50;
     347        pSink->Codec.Opus.msFrame    = 20; /** @todo 20 ms of audio data. Make this configurable? */
    307348
    308349#ifdef VBOX_WITH_STATISTICS
     
    310351        pSink->Codec.STAM.msEncTotal = 0;
    311352#endif
    312 
    313         /* Calculate the maximum frame size. */
    314         pSink->Codec.Opus.csFrameMax = AVREC_OPUS_HZ_MAX       /* Maximum sample rate Opus can handle */
    315                                      * pCodecParms->cChannels; /* Number of channels */
     353    }
     354    else
     355    {
     356        if (pEnc)
     357        {
     358            opus_encoder_destroy(pEnc);
     359            pEnc = NULL;
     360        }
     361
     362        LogRel(("VideoRec: Error creating sink (%Rrc)\n", rc));
    316363    }
    317364
     
    343390            if (pSink->Con.WebM.pWebM)
    344391            {
     392                LogRel2(("VideoRec: Finished recording audio to file '%s' (%zu bytes)\n",
     393                         pSink->Con.WebM.pWebM->GetFileName().c_str(), pSink->Con.WebM.pWebM->GetFileSize()));
     394
    345395                int rc2 = pSink->Con.WebM.pWebM->Close();
    346396                AssertRC(rc2);
     
    392442
    393443#ifdef VBOX_WITH_LIBOPUS
    394     /* If we only record audio, create our own WebM writer instance here. */
    395     if (pSink->Con.Parms.enmType == AVRECCONTAINERTYPE_WEBM)
    396     {
    397         pSink->Con.WebM.pWebM = new WebMWriter();
    398         rc = pSink->Con.WebM.pWebM->Create(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "DrvAudioVideoRec.webm", /** @todo Make this configurable. */
    399                                            RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
    400                                            WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_None);
    401         if (RT_SUCCESS(rc))
    402             rc = pSink->Con.WebM.pWebM->AddAudioTrack(pSink->Codec.Parms.uHz, pCfgReq->Props.cChannels, pCfgReq->Props.cBits,
    403                                                       &pSink->Con.WebM.uTrack);
    404     }
    405 
    406     if (RT_FAILURE(rc))
    407         return rc;
    408 
    409     rc = RTCircBufCreate(&pStreamAV->pCircBuf, (pSink->Codec.Opus.csFrame * pSink->Codec.Parms.cChannels) * sizeof(uint16_t));
     444    const unsigned cFrames = 2; /** @todo Use the PreRoll param for that? */
     445
     446    const uint32_t csFrame = pSink->Codec.Parms.uHz / (1000 /* s in ms */ / pSink->Codec.Opus.msFrame);
     447    const uint32_t cbFrame = csFrame * pSink->Codec.Parms.cChannels * (pSink->Codec.Parms.cBits / 8 /* Bytes */);
     448
     449    rc = RTCircBufCreate(&pStreamAV->pCircBuf, cbFrame * cFrames);
    410450    if (RT_SUCCESS(rc))
    411451    {
     
    494534
    495535    AVRECCONTAINERPARMS ContainerParms;
    496     ContainerParms.enmType = AVRECCONTAINERTYPE_MAIN_CONSOLE; /** @todo Make this configurable. */
     536    ContainerParms.enmType = AVRECCONTAINERTYPE_WEBM; /** @todo Make this configurable. */
    497537
    498538    AVRECCODECPARMS CodecParms;
     
    594634    size_t  cbSrc;
    595635
    596     const uint32_t csFrame = pSink->Codec.Opus.csFrame;
    597     const uint32_t cbFrame = PDMAUDIOSTREAMCFG_F2B(pStreamAV->pCfg, csFrame);
     636    const uint32_t csFrame = pSink->Codec.Parms.uHz / (1000 /* s in ms */ / pSink->Codec.Opus.msFrame);
     637    const uint32_t cbFrame = csFrame * pSink->Codec.Parms.cChannels * (pSink->Codec.Parms.cBits / 8 /* Bytes */);
    598638
    599639    while (RTCircBufUsed(pCircBuf) >= cbFrame)
  • trunk/src/VBox/Main/src-client/EbmlWriter.cpp

    r68333 r68338  
    583583
    584584        pTrack->Audio.uHz     = uHz;
    585         pTrack->Audio.csFrame = pTrack->Audio.uHz / 50; /** @todo 20 ms of audio data. Make this configurable? */
     585        pTrack->Audio.csFrame = pTrack->Audio.uHz / (1000 /* s in ms */ / 20); /** @todo 20 ms of audio data. Make this configurable? */
    586586
    587587        OpusPrivData opusPrivData(uHz, cChannels);
     
    594594              .serializeData(MkvElem_CodecPrivate,            &opusPrivData, sizeof(opusPrivData))
    595595              .serializeUnsignedInteger(MkvElem_CodecDelay,   0)
    596               .serializeUnsignedInteger(MkvElem_SeekPreRoll,  80000000) /* 80ms in ns. */
     596              .serializeUnsignedInteger(MkvElem_SeekPreRoll,  80 * 1000000) /* 80ms in ns. */
    597597              .subStart(MkvElem_Audio)
    598598                  .serializeFloat(MkvElem_SamplingFrequency,  (float)uHz)
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