VirtualBox

Changeset 65212 in vbox for trunk/src


Ignore:
Timestamp:
Jan 9, 2017 3:57:02 PM (8 years ago)
Author:
vboxsync
Message:

VideoRec: Update.

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

Legend:

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

    r65205 r65212  
    194194    PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
    195195
    196     pThis->enmMode = AVRECMODE_AUDIO;
     196    pThis->enmMode = AVRECMODE_AUDIO; /** @todo Fix mode! */
    197197
    198198    int rc;
     
    205205            {
    206206                pThis->pEBML = new WebMWriter();
    207                 pThis->pEBML->create("/tmp/test.webm", WebMWriter::Mode_Audio); /** @todo FIX! */
     207                rc = pThis->pEBML->create("/tmp/test.webm", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
     208                                          WebMWriter::Mode_Audio, /** @todo Fix path! */
     209                                          WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_None);
    208210                break;
    209211            }
     
    211213            case AVRECMODE_AUDIO_VIDEO:
    212214            {
     215                rc = VERR_NOT_SUPPORTED;
    213216                break;
    214217            }
  • trunk/src/VBox/Main/src-client/EbmlWriter.cpp

    r65198 r65212  
    4949
    5050    /** Creates EBML output file. */
    51     inline int create(const char *a_pszFilename)
    52     {
    53         return RTFileOpen(&m_File, a_pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE);
     51    inline int create(const char *a_pszFilename, uint64_t fOpen)
     52    {
     53        return RTFileOpen(&m_File, a_pszFilename, fOpen);
    5454    }
    5555
     
    143143        writeSize(sizeof(double));
    144144        writeUnsignedInteger(*reinterpret_cast<uint64_t*>(&value));
     145        return *this;
     146    }
     147
     148    /** Serializes binary data. */
     149    inline Ebml &serializeData(EbmlClassId classId, const void *pvData, size_t cbData)
     150    {
     151        writeClassId(classId);
     152        writeSize(cbData);
     153        write(pvData, cbData);
    145154        return *this;
    146155    }
     
    227236    };
    228237
     238#ifdef VBOX_WITH_AUDIO_VIDEOREC
     239# pragma pack(push)
     240# pragma pack(1)
     241    /** Opus codec private data.
     242     *  Taken from: https://wiki.xiph.org/MatroskaOpus */
     243    struct OpusPrivData
     244    {
     245        uint8_t  au8Head[8]       = { 0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64 };
     246        uint8_t  u8Version        = 1;
     247        uint8_t  c8Channels;
     248        uint16_t u16PreSkip       = 0;
     249        uint32_t u32SampleRate;
     250        uint16_t u16Gain          = 0;
     251        uint8_t  u8Mapping_family = 0;
     252    };
     253# pragma pack(pop)
     254#endif /* VBOX_WITH_AUDIO_VIDEOREC */
     255
    229256    /** Operation mode. */
    230     WebMWriter::Mode m_enmMode;
    231 
    232     bool            m_fDebug;
    233     int64_t         m_iLastPtsMs;
    234     int64_t         m_iInitialPtsMs;
    235     vpx_rational_t  m_Framerate;
    236 
    237     uint64_t        m_uPositionReference;
    238     uint64_t        m_uSeekInfoPos;
    239     uint64_t        m_uSegmentInfoPos;
    240     uint64_t        m_uTrackPos;
    241     uint64_t        m_uCuePos;
    242     uint64_t        m_uClusterPos;
    243 
    244     uint64_t        m_uTrackIdPos;
    245 
    246     uint64_t        m_uStartSegment;
    247 
    248     uint32_t        m_uClusterTimecode;
    249     bool            m_bClusterOpen;
    250 
    251     std::list<CueEntry> m_CueList;
    252 
    253     Ebml                m_Ebml;
     257    WebMWriter::Mode       m_enmMode;
     258    /** Audio codec to use. */
     259    WebMWriter::AudioCodec m_enmAudioCodec;
     260    /** Video codec to use. */
     261    WebMWriter::VideoCodec m_enmVideoCodec;
     262
     263    bool                   m_fDebug;
     264
     265    /** Timestamp of initial PTS (Presentation Time Stamp). */
     266    int64_t                m_tsInitialPtsMs;
     267    /** Timestamp of last written PTS (Presentation Time Stamp). */
     268    int64_t                m_tsLastPtsMs;
     269
     270    vpx_rational_t         m_Framerate;
     271
     272    /** Start offset (in bytes) of current segment. */
     273    uint64_t               m_offSegCurStart;
     274
     275    /** Start offset (in bytes) of seeking info segment. */
     276    uint64_t               m_offSegSeekInfoStart;
     277    /** Offset (in bytes) for current seek info element. */
     278    uint64_t               m_offSeekInfo;
     279
     280    /** Start offset (in bytes) of tracks segment. */
     281    uint64_t               m_offSegTracksStart;
     282
     283    /** Absolute position of cue segment. */
     284    uint64_t               m_uCuePos;
     285    /** List of cue points. Needed for seeking table. */
     286    std::list<CueEntry>    m_lstCue;
     287
     288    uint64_t               m_uTrackIdPos;
     289
     290    /** Timestamp (in ms) when the current cluster has been opened. */
     291    uint32_t               m_tsClusterOpenMs;
     292    /** Whether we're currently in an opened cluster segment. */
     293    bool                   m_fClusterOpen;
     294    /** Absolute position (in bytes) of current cluster within file.
     295     *  Needed for seeking info table. */
     296    uint64_t               m_offSegClusterStart;
     297
     298    Ebml                   m_Ebml;
    254299
    255300public:
    256301
    257302    WebMWriter_Impl() :
    258         m_enmMode(WebMWriter::Mode_Unknown),
    259         m_fDebug(false),
    260         m_iLastPtsMs(-1),
    261         m_iInitialPtsMs(-1),
    262         m_Framerate(),
    263         m_uPositionReference(0),
    264         m_uSeekInfoPos(0),
    265         m_uSegmentInfoPos(0),
    266         m_uTrackPos(0),
    267         m_uCuePos(0),
    268         m_uClusterPos(0),
    269         m_uTrackIdPos(0),
    270         m_uStartSegment(0),
    271         m_uClusterTimecode(0),
    272         m_bClusterOpen(false) {}
     303          m_enmMode(WebMWriter::Mode_Unknown)
     304        , m_fDebug(false)
     305        , m_tsInitialPtsMs(-1)
     306        , m_tsLastPtsMs(-1)
     307        , m_Framerate()
     308        , m_offSegCurStart(0)
     309        , m_offSegSeekInfoStart(0)
     310        , m_offSeekInfo(0)
     311        , m_offSegTracksStart(0)
     312        , m_uCuePos(0)
     313        , m_uTrackIdPos(0)
     314        , m_tsClusterOpenMs(0)
     315        , m_fClusterOpen(false)
     316        , m_offSegClusterStart(0) {}
    273317
    274318    void writeHeader(const vpx_codec_enc_cfg_t *a_pCfg, const struct vpx_rational *a_pFps)
     
    286330        m_Ebml.subStart(Segment);
    287331
    288         m_uPositionReference = RTFileTell(m_Ebml.getFile());
    289332        m_Framerate = *a_pFps;
    290333
     334        /* Save offset of current segment. */
     335        m_offSegCurStart = RTFileTell(m_Ebml.getFile());
     336
    291337        writeSeekInfo();
    292338
    293         m_uTrackPos = RTFileTell(m_Ebml.getFile());
     339        /* Save offset of upcoming tracks segment. */
     340        m_offSegTracksStart = RTFileTell(m_Ebml.getFile());
    294341
    295342        m_Ebml.subStart(Tracks);
     
    329376            /** @todo Implement track's "Language" property? Currently this defaults to English ("eng"). */
    330377
     378            OpusPrivData opusPrivData;
     379
    331380            m_Ebml.serializeUnsignedInteger(TrackUID, 1 /* UID */, 4)
    332381                  .serializeUnsignedInteger(TrackType, 2 /* Audio */)
    333382                  .serializeString(CodecID, "A_OPUS")
     383                  .serializeData(CodecPrivate, &opusPrivData, sizeof(opusPrivData))
    334384                  .subStart(Audio)
    335385                  .serializeFloat(SamplingFrequency, 44100.0)
     
    347397    void writeBlock(const vpx_codec_enc_cfg_t *a_pCfg, const vpx_codec_cx_pkt_t *a_pPkt)
    348398    {
     399        /* Calculate the PTS of this frame in milliseconds. */
     400        int64_t iPtsMs = a_pPkt->data.frame.pts * 1000
     401                       * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
     402
     403        if (iPtsMs <= m_tsLastPtsMs)
     404            iPtsMs = m_tsLastPtsMs + 1;
     405
     406        m_tsLastPtsMs = iPtsMs;
     407
     408        if (m_tsInitialPtsMs < 0)
     409          m_tsInitialPtsMs = m_tsLastPtsMs;
     410
     411        /* Calculate the relative time of this block. */
    349412        uint16_t uBlockTimecode = 0;
    350         int64_t  iPtsMs;
    351         bool     bStartCluster = false;
    352 
    353         /* Calculate the PTS of this frame in milliseconds. */
    354         iPtsMs = a_pPkt->data.frame.pts * 1000
    355                  * (uint64_t) a_pCfg->g_timebase.num / a_pCfg->g_timebase.den;
    356         if (iPtsMs <= m_iLastPtsMs)
    357             iPtsMs = m_iLastPtsMs + 1;
    358         m_iLastPtsMs = iPtsMs;
    359 
    360         if (m_iInitialPtsMs < 0)
    361           m_iInitialPtsMs = m_iLastPtsMs;
    362 
    363         /* Calculate the relative time of this block. */
    364         if (iPtsMs - m_uClusterTimecode > 65536)
    365             bStartCluster = 1;
     413        bool     fClusterStart  = false;
     414
     415        if (iPtsMs - m_tsClusterOpenMs > 65536)
     416            fClusterStart = true;
    366417        else
    367             uBlockTimecode = static_cast<uint16_t>(iPtsMs - m_uClusterTimecode);
    368 
    369         int fKeyframe = (a_pPkt->data.frame.flags & VPX_FRAME_IS_KEY);
    370         if (bStartCluster || fKeyframe)
     418            uBlockTimecode = static_cast<uint16_t>(iPtsMs - m_tsClusterOpenMs);
     419
     420        bool fKeyframe = RT_BOOL(a_pPkt->data.frame.flags & VPX_FRAME_IS_KEY);
     421
     422        if (   fClusterStart
     423            || fKeyframe)
    371424        {
    372             if (m_bClusterOpen)
     425            if (m_fClusterOpen)
    373426                m_Ebml.subEnd(Cluster);
    374427
    375428            /* Open a new cluster. */
    376429            uBlockTimecode = 0;
    377             m_bClusterOpen = true;
    378             m_uClusterTimecode = (uint32_t)iPtsMs;
    379             m_uClusterPos = RTFileTell(m_Ebml.getFile());
     430            m_fClusterOpen = true;
     431            m_tsClusterOpenMs = (uint32_t)iPtsMs;
     432            m_offSegClusterStart = RTFileTell(m_Ebml.getFile());
    380433            m_Ebml.subStart(Cluster)
    381                   .serializeUnsignedInteger(Timecode, m_uClusterTimecode);
     434                  .serializeUnsignedInteger(Timecode, m_tsClusterOpenMs);
    382435
    383436            /* Save a cue point if this is a keyframe. */
    384437            if (fKeyframe)
    385438            {
    386                 CueEntry cue(m_uClusterTimecode, m_uClusterPos);
    387                 m_CueList.push_back(cue);
     439                CueEntry cue(m_tsClusterOpenMs, m_offSegClusterStart);
     440                m_lstCue.push_back(cue);
    388441            }
    389442        }
     
    400453    void writeFooter(uint32_t a_u64Hash)
    401454    {
    402         if (m_bClusterOpen)
     455        if (m_fClusterOpen)
    403456            m_Ebml.subEnd(Cluster);
    404457
    405458        m_uCuePos = RTFileTell(m_Ebml.getFile());
    406459        m_Ebml.subStart(Cues);
    407         for (std::list<CueEntry>::iterator it = m_CueList.begin(); it != m_CueList.end(); ++it)
     460        for (std::list<CueEntry>::iterator it = m_lstCue.begin(); it != m_lstCue.end(); ++it)
    408461        {
    409462          m_Ebml.subStart(CuePoint)
     
    411464                .subStart(CueTrackPositions)
    412465                .serializeUnsignedInteger(CueTrack, 1)
    413                 .serializeUnsignedInteger(CueClusterPosition, it->loc - m_uPositionReference, 8)
     466                .serializeUnsignedInteger(CueClusterPosition, it->loc - m_offSegCurStart, 8)
    414467                .subEnd(CueTrackPositions)
    415468                .subEnd(CuePoint);
     
    434487private:
    435488
    436     void writeSeekInfo()
     489    void writeSeekInfo(void)
    437490    {
    438491        uint64_t uPos = RTFileTell(m_Ebml.getFile());
    439         if (m_uSeekInfoPos)
    440             RTFileSeek(m_Ebml.getFile(), m_uSeekInfoPos, RTFILE_SEEK_BEGIN, NULL);
     492        if (m_offSegSeekInfoStart)
     493            RTFileSeek(m_Ebml.getFile(), m_offSegSeekInfoStart, RTFILE_SEEK_BEGIN, NULL);
    441494        else
    442             m_uSeekInfoPos = uPos;
     495            m_offSegSeekInfoStart = uPos;
    443496
    444497        m_Ebml.subStart(SeekHead)
     
    446499              .subStart(Seek)
    447500              .serializeUnsignedInteger(SeekID, Tracks)
    448               .serializeUnsignedInteger(SeekPosition, m_uTrackPos - m_uPositionReference, 8)
     501              .serializeUnsignedInteger(SeekPosition, m_offSegTracksStart - m_offSegCurStart, 8)
    449502              .subEnd(Seek)
    450503
    451504              .subStart(Seek)
    452505              .serializeUnsignedInteger(SeekID, Cues)
    453               .serializeUnsignedInteger(SeekPosition, m_uCuePos - m_uPositionReference, 8)
     506              .serializeUnsignedInteger(SeekPosition, m_uCuePos - m_offSegCurStart, 8)
    454507              .subEnd(Seek)
    455508
    456509              .subStart(Seek)
    457510              .serializeUnsignedInteger(SeekID, Info)
    458               .serializeUnsignedInteger(SeekPosition, m_uSegmentInfoPos - m_uPositionReference, 8)
     511              .serializeUnsignedInteger(SeekPosition, m_offSeekInfo - m_offSegCurStart, 8)
    459512              .subEnd(Seek)
    460513
    461               .subEnd(SeekHead);
     514        .subEnd(SeekHead);
    462515
    463516        int64_t iFrameTime = (int64_t)1000 * m_Framerate.den / m_Framerate.num;
    464         m_uSegmentInfoPos = RTFileTell(m_Ebml.getFile());
     517        m_offSeekInfo = RTFileTell(m_Ebml.getFile());
    465518
    466519        char szVersion[64];
     
    470523        m_Ebml.subStart(Info)
    471524              .serializeUnsignedInteger(TimecodeScale, 1000000)
    472               .serializeFloat(Segment_Duration, m_iLastPtsMs + iFrameTime - m_iInitialPtsMs)
     525              .serializeFloat(Segment_Duration, m_tsLastPtsMs + iFrameTime - m_tsInitialPtsMs)
    473526              .serializeString(MuxingApp, szVersion)
    474527              .serializeString(WritingApp, szVersion)
     
    477530};
    478531
    479 WebMWriter::WebMWriter() : m_Impl(new WebMWriter_Impl()) {}
    480 
    481 WebMWriter::~WebMWriter()
    482 {
    483     delete m_Impl;
    484 }
    485 
    486 int WebMWriter::create(const char *a_pszFilename, WebMWriter::Mode a_enmMode)
    487 {
    488     m_Impl->m_enmMode = a_enmMode;
    489 
    490     return m_Impl->m_Ebml.create(a_pszFilename);
    491 }
    492 
    493 void WebMWriter::close()
    494 {
    495     m_Impl->m_Ebml.close();
     532WebMWriter::WebMWriter(void) : m_pImpl(new WebMWriter_Impl()) {}
     533
     534WebMWriter::~WebMWriter(void)
     535{
     536    if (m_pImpl)
     537        delete m_pImpl;
     538}
     539
     540int WebMWriter::create(const char *a_pszFilename, uint64_t a_fOpen, WebMWriter::Mode a_enmMode,
     541                       WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec)
     542{
     543    m_pImpl->m_enmMode       = a_enmMode;
     544    m_pImpl->m_enmAudioCodec = a_enmAudioCodec;
     545    m_pImpl->m_enmVideoCodec = a_enmVideoCodec;
     546
     547    return m_pImpl->m_Ebml.create(a_pszFilename, a_fOpen);
     548}
     549
     550void WebMWriter::close(void)
     551{
     552    m_pImpl->m_Ebml.close();
    496553}
    497554
     
    500557    try
    501558    {
    502         m_Impl->writeHeader(a_pCfg, a_pFps);
     559        m_pImpl->writeHeader(a_pCfg, a_pFps);
    503560    }
    504561    catch(int rc)
     
    513570    try
    514571    {
    515         m_Impl->writeBlock(a_pCfg, a_pPkt);
     572        m_pImpl->writeBlock(a_pCfg, a_pPkt);
    516573    }
    517574    catch(int rc)
     
    526583    try
    527584    {
    528         m_Impl->writeFooter(a_u64Hash);
     585        m_pImpl->writeFooter(a_u64Hash);
    529586    }
    530587    catch(int rc)
     
    537594uint64_t WebMWriter::getFileSize()
    538595{
    539     return m_Impl->m_Ebml.getFileSize();
     596    return m_pImpl->m_Ebml.getFileSize();
    540597}
    541598
    542599uint64_t WebMWriter::getAvailableSpace()
    543600{
    544     return m_Impl->m_Ebml.getAvailableSpace();
    545 }
    546 
     601    return m_pImpl->m_Ebml.getAvailableSpace();
     602}
     603
  • trunk/src/VBox/Main/src-client/EbmlWriter.h

    r65197 r65212  
    2828#endif
    2929
     30#include <iprt/file.h>
     31
    3032class WebMWriter_Impl;
    3133
     
    3436
    3537public:
     38
     39    /**
     40     * Supported audio codecs.
     41     */
     42    enum AudioCodec
     43    {
     44        /** No audio codec specified. */
     45        AudioCodec_Unknown = 0,
     46        /** Opus. */
     47        AudioCodec_Opus    = 1
     48    };
     49
     50    /**
     51     * Supported video codecs.
     52     */
     53    enum VideoCodec
     54    {
     55        /** No video codec specified. */
     56        VideoCodec_None = 0,
     57        /** VP8. */
     58        VideoCodec_VP8  = 1
     59    };
     60
     61    struct BlockData
     62    {
     63        void  *pvData;
     64        size_t cbData;
     65    };
    3666
    3767    /**
     
    4474        /** Only writes audio. */
    4575        Mode_Audio       = 1,
    46         /** Only Writes video. */
     76        /** Only writes video. */
    4777        Mode_Video       = 2,
    4878        /** Writes audio and video. */
     
    5989     *
    6090     * @param   a_pszFilename   Name of the file to create.
     91     * @param   a_fOpen         File open mode of type RTFILE_O_.
    6192     * @param   a_enmMode       Operation mode.
     93     * @param   a_enmAudioCodec Audio codec to use.
     94     * @param   a_enmVideoCodec Video codec to use.
    6295     *
    6396     * @returns VBox status code. */
    64     int create(const char *a_pszFilename, WebMWriter::Mode a_enmMode);
     97    int create(const char *a_pszFilename, uint64_t a_fOpen, WebMWriter::Mode a_enmMode,
     98               WebMWriter::AudioCodec a_enmAudioCodec, WebMWriter::VideoCodec a_enmVideoCodec);
    6599
    66     /* Closes output file. */
     100    /** Closes output file. */
    67101    void close();
    68102
     
    116150    /** WebMWriter implementation.
    117151     *  To isolate some include files. */
    118     WebMWriter_Impl *m_Impl;
     152    WebMWriter_Impl *m_pImpl;
    119153
    120154    DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(WebMWriter);
  • trunk/src/VBox/Main/src-client/VideoRec.cpp

    r65197 r65212  
    647647     * other important file, causing unintentional data loss. */
    648648
    649     int rc = pStream->pEBML->create(pszFile, WebMWriter::Mode_AudioVideo); /** @todo Make mode configurable. */
     649    /** @todo Make mode configurable. */
     650#ifdef VBOX_WITH_AUDIO_VIDEOREC
     651    WebMWriter::Mode enmMode = WebMWriter::Mode_AudioVideo;
     652#else
     653    WebMWriter::Mode enmMode = WebMWriter::Mode_Video;
     654#endif
     655
     656    int rc = pStream->pEBML->create(pszFile, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE, enmMode,
     657                                    WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_VP8);
    650658    if (RT_FAILURE(rc))
    651659    {
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