Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/stream_out/sdi/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 25 kB image not shown  

Quelle  DBMSDIOutput.cpp   Sprache: C

 

/*****************************************************************************
 * DBMSDIOutput.cpp: Decklink SDI Output
 *****************************************************************************
 * Copyright © 2014-2016 VideoLAN and VideoLAN Authors
 *                  2018 VideoLabs
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <algorithm>
#include <cstdlib>

#include <vlc_common.h>
#include <vlc_es.h>
#include <vlc_picture.h>
#include <vlc_interrupt.h>

#include "DBMHelper.hpp"
#include "DBMSDIOutput.hpp"
#include "SDIStream.hpp"
#include "SDIAudioMultiplex.hpp"
#include "SDIGenerator.hpp"
#include "Ancillary.hpp"
#include "V210.hpp"

#ifndef _WIN32
#include <DeckLinkAPIDispatch.cpp>
#endif
#include <DeckLinkAPIVersion.h>
#if BLACKMAGIC_DECKLINK_API_VERSION < 0x0b010000
 #define IID_IDeckLinkProfileAttributes IID_IDeckLinkAttributes
 #define IDeckLinkProfileAttributes IDeckLinkAttributes
#endif

#include "sdiout.hpp"

#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif

#define DECKLINK_CARD_BUFFER (CLOCK_FREQ)
#define DECKLINK_PREROLL (CLOCK_FREQ*3/4)
#define DECKLINK_SCHED_OFFSET (CLOCK_FREQ/20)

static_assert(DECKLINK_CARD_BUFFER > DECKLINK_PREROLL + DECKLINK_SCHED_OFFSET, "not in card buffer limits");

using namespace sdi_sout;

DBMSDIOutput::DBMSDIOutput(sout_stream_t *p_stream) :
    SDIOutput(p_stream)
{
    p_card = NULL;
    p_output = NULL;
    clock.system_reference = VLC_TICK_INVALID;
    clock.offset = 0;
    lasttimestamp = 0;
    b_running = false;
    streamStartTime = VLC_TICK_INVALID;
    vlc_mutex_init(&feeder.lock);
    vlc_cond_init(&feeder.cond);
    feeder.canceled = false;
}

DBMSDIOutput::~DBMSDIOutput()
{
    if(p_output)
    {
        while(!isDrained())
            vlc_tick_wait(vlc_tick_now() + CLOCK_FREQ/60);

        vlc_mutex_lock(&feeder.lock);
        feeder.canceled = true;
        vlc_cond_signal(&feeder.cond);
        vlc_mutex_unlock(&feeder.lock);

        vlc_join(feeder.thread, NULL);
    }

    es_format_Clean(&video.configuredfmt);
    if(p_output)
    {
        BMDTimeValue out;
        p_output->StopScheduledPlayback(lasttimestamp, &out, timescale);
        p_output->DisableVideoOutput();
        p_output->DisableAudioOutput();
        p_output->Release();
    }
    if(p_card)
        p_card->Release();
}

AbstractStream *DBMSDIOutput::Add(const es_format_t *fmt)
{
    AbstractStream *s = SDIOutput::Add(fmt);
    if(s)
    {
        msg_Dbg(p_stream, "accepted %s %4.4s",
                          s->getID().toString().c_str(), (const char *) &fmt->i_codec);
    }
    else
    {
        msg_Err(p_stream, "rejected es id %d %4.4s",
                          fmt->i_id, (const char *) &fmt->i_codec);
    }

    return s;
}

#define CHECK(message) do { \
    if (result != S_OK) \
    { \
    const char *psz_err = Decklink::Helper::ErrorToString(result); \
    if(psz_err)\
    msg_Err(p_stream, message ": %s", psz_err); \
    else \
    msg_Err(p_stream, message ":0x%" PRIHR, result); \
    goto error; \
} \
} while(0)

HRESULT STDMETHODCALLTYPE DBMSDIOutput::QueryInterface( REFIID, LPVOID * )
{
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE DBMSDIOutput::AddRef()
{
    return 1;
}

ULONG STDMETHODCALLTYPE DBMSDIOutput::Release()
{
    return 1;
}

HRESULT STDMETHODCALLTYPE DBMSDIOutput::ScheduledFrameCompleted
    (IDeckLinkVideoFrame *, BMDOutputFrameCompletionResult result)
{
    if(result == bmdOutputFrameDropped)
        msg_Warn(p_stream, "dropped frame");
    else if(result == bmdOutputFrameDisplayedLate)
        msg_Warn(p_stream, "late frame");

#ifdef _WIN32
    BOOL b_active;
#else
    bool b_active;
#endif
    vlc_mutex_locker locker(&feeder.lock);
    if((S_OK == p_output->IsScheduledPlaybackRunning(&b_active)) && b_active)
        vlc_cond_signal(&feeder.cond);

    return S_OK;
}

HRESULT DBMSDIOutput::ScheduledPlaybackHasStopped (void)
{
    return S_OK;
}

int DBMSDIOutput::Open()
{
    HRESULT result;
    IDeckLinkIterator *decklink_iterator = NULL;

    int i_card_index = var_InheritInteger(p_stream, CFG_PREFIX "card-index");

    if (i_card_index < 0)
    {
        msg_Err(p_stream, "Invalid card index %d", i_card_index);
        goto error;
    }

    decklink_iterator = CreateDeckLinkIteratorInstance();
    if (!decklink_iterator)
    {
        msg_Err(p_stream, "DeckLink drivers not found.");
        goto error;
    }

    for(int i = 0; i <= i_card_index; ++i)
    {
        if (p_card)
        {
            p_card->Release();
            p_card = NULL;
        }
        result = decklink_iterator->Next(&p_card);
        CHECK("Card not found");
    }

    decklink_str_t tmp_name;
    char *psz_model_name;
    result = p_card->GetModelName(&tmp_name);
    CHECK("Unknown model name");
    psz_model_name = DECKLINK_STRDUP(tmp_name);
    DECKLINK_FREE(tmp_name);

    msg_Dbg(p_stream, "Opened DeckLink PCI card %s", psz_model_name);
    free(psz_model_name);

    void *pv;
    result = p_card->QueryInterface(IID_IDeckLinkOutput, &pv);
    CHECK("No outputs");
    p_output = static_cast<IDeckLinkOutput*>(pv);

    decklink_iterator->Release();

    if(vlc_clone(&feeder.thread, feederThreadCallback, this))
        goto error;

    return VLC_SUCCESS;

error:
    if (p_output)
    {
        p_output->Release();
        p_output = NULL;
    }
    if (p_card)
    {
        p_card->Release();
        p_output = NULL;
    }
    if (decklink_iterator)
        decklink_iterator->Release();

    return VLC_EGENERIC;
}

int DBMSDIOutput::ConfigureAudio(const audio_format_t *)
{
    HRESULT result;
    IDeckLinkProfileAttributes *p_attributes = NULL;

    if(FAKE_DRIVER)
        return VLC_SUCCESS;

    if(!p_output)
        return VLC_EGENERIC;

    if(!video.configuredfmt.i_codec && b_running)
        return VLC_EGENERIC;

    if (audio.i_channels > 0)
    {
        uint8_t maxchannels = audioMultiplex->config.getMultiplexedFramesCount() * 2;

        void *pv;
        result = p_card->QueryInterface(IID_IDeckLinkProfileAttributes, &pv);
        CHECK("Could not get IDeckLinkAttributes");
        p_attributes = static_cast<IDeckLinkProfileAttributes*>(pv);

        int64_t i64;
        result = p_attributes->GetInt(BMDDeckLinkMaximumAudioChannels, &i64);
        CHECK("Could not get BMDDeckLinkMaximumAudioChannels");
        if(i64 < maxchannels)
        {
            msg_Err(p_stream, "requested channels %" PRIu8 " exceeds supported maximum: %" PRId64,
                    maxchannels, i64);
            goto error;
        }

        msg_Dbg(p_stream, "configuring audio output with %d", maxchannels);
        result = p_output->EnableAudioOutput(
                    bmdAudioSampleRate48kHz,
                    bmdAudioSampleType16bitInteger,
                    maxchannels,
                    bmdAudioOutputStreamTimestamped);
        CHECK("Could not start audio output");

        if(S_OK != p_output->BeginAudioPreroll())
        {
            p_output->DisableAudioOutput();
            goto error;
        }

        audio.b_configured = true;

        p_attributes->Release();
    }
    return VLC_SUCCESS;

error:
    if(p_attributes)
        p_attributes->Release();
    return VLC_EGENERIC;
}

static BMDVideoConnection getVConn(const char *psz)
{
    BMDVideoConnection conn = bmdVideoConnectionSDI;

    if(!psz)
        return conn;

    if (!strcmp(psz, "sdi"))
        conn = bmdVideoConnectionSDI;
    else if (!strcmp(psz, "hdmi"))
        conn = bmdVideoConnectionHDMI;
    else if (!strcmp(psz, "opticalsdi"))
        conn = bmdVideoConnectionOpticalSDI;
    else if (!strcmp(psz, "component"))
        conn = bmdVideoConnectionComponent;
    else if (!strcmp(psz, "composite"))
        conn = bmdVideoConnectionComposite;
    else if (!strcmp(psz, "svideo"))
        conn = bmdVideoConnectionSVideo;

    return conn;
}

int DBMSDIOutput::ConfigureVideo(const video_format_t *vfmt)
{
    HRESULT result;
    union {
        BMDDisplayMode id;
        char str[4];
    } wanted_mode;
    wanted_mode.id = bmdModeUnknown;
    IDeckLinkConfiguration *p_config = NULL;
    IDeckLinkProfileAttributes *p_attributes = NULL;
    IDeckLinkDisplayMode *p_display_mode = NULL;
    char *psz_string = NULL;
    video_format_t *fmt = &video.configuredfmt.video;
    void *pv;

    if(FAKE_DRIVER)
    {
        video_format_Copy(fmt, vfmt);
        fmt->i_chroma = !video.tenbits ? VLC_CODEC_UYVY : VLC_CODEC_I422_10L;
        fmt->i_frame_rate = (unsigned) frameduration;
        fmt->i_frame_rate_base = (unsigned) timescale;
        video.configuredfmt.i_codec = fmt->i_chroma;
        return VLC_SUCCESS;
    }

    if(!p_output)
        return VLC_EGENERIC;

    if(!video.configuredfmt.i_codec && b_running)
        return VLC_EGENERIC;

    /* Now configure card */
    if(!p_output)
        return VLC_EGENERIC;

    result = p_card->QueryInterface(IID_IDeckLinkConfiguration, &pv);
    CHECK("Could not get config interface");
    p_config = static_cast<IDeckLinkConfiguration*>(pv);

    psz_string = var_InheritString(p_stream, CFG_PREFIX "mode");
    if(psz_string)
    {
        size_t len = strlen(psz_string);
        if (len > 4)
        {
            msg_Err(p_stream, "Invalid mode %s", psz_string);
            free(psz_string);
            goto error;
        }
        strncpy(wanted_mode.str, psz_string, 4);
        free(psz_string);
    }

    /* Read attributes */
    result = p_card->QueryInterface(IID_IDeckLinkProfileAttributes, &pv);
    CHECK("Could not get IDeckLinkAttributes");
    p_attributes = static_cast<IDeckLinkProfileAttributes*>(pv);

#ifdef _WIN32
    LONGLONG iconn;
#else
    int64_t iconn;
#endif
    BMDVideoConnection vconn;
    result = p_attributes->GetInt(BMDDeckLinkVideoOutputConnections, &iconn); /* reads mask */
    CHECK("Could not get BMDDeckLinkVideoOutputConnections");

    psz_string = var_InheritString(p_stream, CFG_PREFIX "video-connection");
    vconn = getVConn(psz_string);
    free(psz_string);

    result = p_config->SetInt(bmdDeckLinkConfigVideoOutputConnection, vconn);
    CHECK("Could not set video output connection");

    p_display_mode = Decklink::Helper::MatchDisplayMode(VLC_OBJECT(p_stream),
                                                        p_output, vfmt, wanted_mode.id);
    if(p_display_mode == NULL)
    {
        msg_Err(p_stream, "Could not negotiate a compatible display mode");
        goto error;
    }
    else
    {
        union {
            BMDDisplayMode id;
            char str[4];
        } mode;
        mode.id = p_display_mode->GetDisplayMode();
        msg_Dbg(p_stream, "Selected mode '%4.4s'", mode.str);

        BMDPixelFormat pixelFormat = video.tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV;
        BMDVideoOutputFlags flags = bmdVideoOutputVANC;
        if (mode.id == bmdModeNTSC ||
            mode.id == bmdModeNTSC2398 ||
            mode.id == bmdModePAL)
        {
            flags = bmdVideoOutputVITC;
        }
#ifdef _WIN32
        BOOL supported;
#else
        bool supported;
#endif
#if BLACKMAGIC_DECKLINK_API_VERSION < 0x0b010000
        BMDDisplayModeSupport support = bmdDisplayModeNotSupported;
        result = p_output->DoesSupportVideoMode(mode.id,
                                                pixelFormat,
                                                flags,
                                                &support,
                                                NULL);
        supported = (support != bmdDisplayModeNotSupported);
#else
        result = p_output->DoesSupportVideoMode(vconn,
                                                mode.id,
                                                pixelFormat,
                                                bmdSupportedVideoModeDefault,
                                                NULL,
                                                &supported);
#endif
        CHECK("Does not support video mode");
        if (!supported)
        {
            msg_Err(p_stream, "Video mode not supported");
            goto error;
        }

        if (p_display_mode->GetWidth() <= 0 || p_display_mode->GetWidth() & 1)
        {
            msg_Err(p_stream, "Unknown video mode specified.");
            goto error;
        }

        result = p_display_mode->GetFrameRate(&frameduration,
                                              ×cale);
        CHECK("Could not read frame rate");

        result = p_output->EnableVideoOutput(mode.id, flags);
        CHECK("Could not enable video output");

        p_output->SetScheduledFrameCompletionCallback(this);

        video_format_Copy(fmt, vfmt);
        fmt->i_width = fmt->i_visible_width = p_display_mode->GetWidth();
        fmt->i_height = fmt->i_visible_height = p_display_mode->GetHeight();
        fmt->i_x_offset = 0;
        fmt->i_y_offset = 0;
        fmt->i_sar_num = 0;
        fmt->i_sar_den = 0;
        fmt->i_chroma = !video.tenbits ? VLC_CODEC_UYVY : VLC_CODEC_I422_10L; /* we will convert to v210 */
        fmt->i_frame_rate = (unsigned) frameduration;
        fmt->i_frame_rate_base = (unsigned) timescale;
        video.configuredfmt.i_codec = fmt->i_chroma;

        char *psz_file = var_InheritString(p_stream, CFG_PREFIX "nosignal-image");
        if(psz_file)
        {
            video.pic_nosignal = sdi::Generator::Picture(VLC_OBJECT(p_stream), psz_file, fmt);
            if (!video.pic_nosignal)
                msg_Err(p_stream, "Could not create no signal picture");
            free(psz_file);
        }
    }

    p_display_mode->Release();
    p_attributes->Release();
    p_config->Release();

    return VLC_SUCCESS;

error:
    if (p_display_mode)
        p_display_mode->Release();
    if(p_attributes)
        p_attributes->Release();
    if (p_config)
        p_config->Release();
    return VLC_EGENERIC;
}

int DBMSDIOutput::StartPlayback()
{
    HRESULT result;
    if(FAKE_DRIVER && !b_running)
    {
        b_running = true;
        return VLC_SUCCESS;
    }
    if(b_running)
        return VLC_EGENERIC;

    if(audio.b_configured)
        p_output->EndAudioPreroll();

    result = p_output->StartScheduledPlayback(streamStartTime, CLOCK_FREQ, 1.0);
    CHECK("Could not start playback");
    b_running = true;
    return VLC_SUCCESS;

error:
    return VLC_EGENERIC;
}

int DBMSDIOutput::FeedOneFrame()
{
    picture_t *p = reinterpret_cast<picture_t *>(videoBuffer.Dequeue());
    if(p)
        return ProcessVideo(p, reinterpret_cast<block_t *>(captionsBuffer.Dequeue()));

    return VLC_SUCCESS;
}

int DBMSDIOutput::FeedAudio(vlc_tick_t start, vlc_tick_t preroll, bool b_truncate)
{
#ifdef SDI_MULTIPLEX_DEBUG
        audioMultiplex->Debug();
#endif
    vlc_tick_t bufferStart = audioMultiplex->bufferStart();
    unsigned i_samples_per_frame =
            audioMultiplex->alignedInterleaveInSamples(bufferStart, SAMPLES_PER_FRAME);

    unsigned buffered = 0;
    while(bufferStart <= (start+preroll) &&
          audioMultiplex->availableVirtualSamples(bufferStart) >= i_samples_per_frame)
    {
        block_t *out = audioMultiplex->Extract(i_samples_per_frame);
        if(out)
        {
#ifdef SDI_MULTIPLEX_DEBUG
              msg_Dbg(p_stream, "extracted %u samples pts %ld i_samples_per_frame %u",
                      out->i_nb_samples, out->i_dts, i_samples_per_frame);
#endif
              if(b_truncate && out->i_pts < start)
              {
#ifdef SDI_MULTIPLEX_DEBUG
                  msg_Err(p_stream,"dropping %u samples at %ld (-%ld)",
                          i_samples_per_frame, out->i_pts, (start - out->i_pts));
#endif
                  block_Release(out);
              }
              else
              {
                  ProcessAudio(out);
              }
        }
        else break;
        bufferStart = audioMultiplex->bufferStart();
        i_samples_per_frame = audioMultiplex->alignedInterleaveInSamples(bufferStart, SAMPLES_PER_FRAME);
        buffered += i_samples_per_frame;
    }

    return buffered > 0 ? VLC_SUCCESS : VLC_EGENERIC;
}

void * DBMSDIOutput::feederThreadCallback(void *me)
{
    vlc_thread_set_name("vlc-DBMSDI");

    reinterpret_cast<DBMSDIOutput *>(me)->feederThread();
    return NULL;
}

void DBMSDIOutput::feederThread()
{
    vlc_tick_t maxdelay = CLOCK_FREQ/60;
    for(;;)
    {
        vlc_mutex_locker locker(&feeder.lock);
        vlc_cond_timedwait(&feeder.cond, &feeder.lock, vlc_tick_now() + maxdelay);
        if (feeder.canceled)
            break;
        doSchedule();
        if(timescale)
            maxdelay = CLOCK_FREQ * frameduration / timescale;
    }
}

int DBMSDIOutput::Process()
{
    if((!p_output && !FAKE_DRIVER))
        return VLC_SUCCESS;

    vlc_mutex_locker locker(&feeder.lock);
    vlc_cond_signal(&feeder.cond);

    return VLC_SUCCESS;
}

int DBMSDIOutput::doSchedule()
{
    const vlc_tick_t preroll = DECKLINK_PREROLL;
    vlc_tick_t next = videoBuffer.NextPictureTime();
    if(next == VLC_TICK_INVALID ||
       (!b_running && !ReachedPlaybackTime(next + preroll + SAMPLES_PER_FRAME*CLOCK_FREQ/48000)))
        return VLC_SUCCESS;

    if(FAKE_DRIVER)
    {
        FeedOneFrame();
        FeedAudio(next, preroll, false);
        b_running = true;
        return VLC_SUCCESS;
    }

    uint32_t bufferedFramesCount;
    uint32_t bufferedAudioCount = 0;
    if(S_OK != p_output->GetBufferedVideoFrameCount(&bufferedFramesCount))
        return VLC_EGENERIC;

    uint32_t bufferedFramesTarget = (uint64_t)timescale*preroll/frameduration/CLOCK_FREQ;
    if( bufferedFramesTarget > bufferedFramesCount )
    {
        for(size_t i=0; i<bufferedFramesTarget - bufferedFramesCount; i++)
        {
            FeedOneFrame();
            if(b_running)
                break;
        }
        p_output->GetBufferedVideoFrameCount(&bufferedFramesCount);
    }

    /* no frames got in ?? */
    if(streamStartTime == VLC_TICK_INVALID)
    {
        assert(bufferedFramesTarget);
        assert(!b_running);
        return VLC_EGENERIC;
    }

    if(audio.b_configured)
    {
        if(S_OK != p_output->GetBufferedAudioSampleFrameCount(&bufferedAudioCount))
            return VLC_EGENERIC;

        uint32_t bufferedAudioTarget = 48000*preroll/CLOCK_FREQ;
        if(bufferedAudioCount < bufferedAudioTarget)
        {
            vlc_tick_t audioSamplesDuration = (bufferedAudioTarget - bufferedAudioCount)
                                            * CLOCK_FREQ / 48000;
            if(b_running)
                FeedAudio(next, audioSamplesDuration, false);
            else
                FeedAudio(streamStartTime, audioSamplesDuration, true);

            p_output->GetBufferedAudioSampleFrameCount(&bufferedAudioCount);
        }
    }

    if(!b_running && bufferedFramesCount >= bufferedFramesTarget)
    {
        msg_Dbg(p_stream, "Preroll end with %d frames/%d samples",
                          bufferedFramesCount, bufferedAudioCount);
        StartPlayback();
    }

    return (bufferedFramesCount < bufferedFramesTarget) ? VLC_EGENERIC : VLC_SUCCESS;
}

int DBMSDIOutput::ProcessAudio(block_t *p_block)
{
    if(FAKE_DRIVER)
    {
        block_Release(p_block);
        return VLC_SUCCESS;
    }

    if (!p_output)
    {
        block_Release(p_block);
        return VLC_EGENERIC;
    }

    uint32_t sampleFrameCount = p_block->i_nb_samples;
    uint32_t written;
    p_block->i_pts -= clock.offset;
    const BMDTimeValue scheduleTime = p_block->i_pts + DECKLINK_SCHED_OFFSET;
    HRESULT result = p_output->ScheduleAudioSamples(
                p_block->p_buffer, p_block->i_nb_samples,
                scheduleTime, CLOCK_FREQ, &written);

    if (result != S_OK)
        msg_Err(p_stream, "Failed to schedule audio sample:0x%" PRIHR, result);
    else
    {
        lasttimestamp = std::max(p_block->i_pts, lasttimestamp);
        if (sampleFrameCount != written)
            msg_Err(p_stream, "Written only %d samples out of %d", written, sampleFrameCount);
    }

    block_Release(p_block);

    return result != S_OK ? VLC_EGENERIC : VLC_SUCCESS;
}

int DBMSDIOutput::ProcessVideo(picture_t *picture, block_t *p_cc)
{
    if (!picture)
        return VLC_EGENERIC;

    checkClockDrift();

    if(video.pic_nosignal && !FAKE_DRIVER)
    {
        BMDTimeValue streamTime;
        double playbackSpeed;
        if(S_OK == p_output->GetScheduledStreamTime(CLOCK_FREQ, &streamTime, &playbackSpeed))
        {
            if(picture->date - streamTime >
               VLC_TICK_FROM_SEC(video.nosignal_delay))
            {
                msg_Info(p_stream, "no signal");
                picture_Hold(video.pic_nosignal);
                video.pic_nosignal->date = streamTime + VLC_TICK_FROM_MS(30);
                doProcessVideo(video.pic_nosignal, NULL);
            }
        }
    }

    return doProcessVideo(picture, p_cc);
}

int DBMSDIOutput::doProcessVideo(picture_t *picture, block_t *p_cc)
{
    HRESULT result;
    int w, h, stride, length, ret = VLC_EGENERIC;
    BMDTimeValue scheduleTime;
    IDeckLinkMutableVideoFrame *pDLVideoFrame = NULL;
    w = video.configuredfmt.video.i_visible_width;
    h = video.configuredfmt.video.i_visible_height;

    if(FAKE_DRIVER)
        goto end;

    result = p_output->CreateVideoFrame(w, h, w*3,
                                        video.tenbits ? bmdFormat10BitYUV : bmdFormat8BitYUV,
                                        bmdFrameFlagDefault, &pDLVideoFrame);
    if(result != S_OK) {
        msg_Err(p_stream, "Failed to create video frame:0x%" PRIHR, result);
        goto error;
    }

    void *frame_bytes;
    pDLVideoFrame->GetBytes((void**)&frame_bytes);
    stride = pDLVideoFrame->GetRowBytes();

    if (video.tenbits)
    {
        IDeckLinkVideoFrameAncillary *vanc;
        void *buf;

        result = p_output->CreateAncillaryData(bmdFormat10BitYUV, &vanc);
        if (result != S_OK) {
            msg_Err(p_stream, "Failed to create vanc:0x%" PRIHR, result);
            goto error;
        }

        result = vanc->GetBufferForVerticalBlankingLine(ancillary.afd_line, &buf);
        if (result != S_OK) {
            msg_Err(p_stream, "Failed to get VBI line %u:0x%" PRIHR, ancillary.afd_line, result);
            goto error;
        }

        sdi::AFD afd(ancillary.afd, ancillary.ar);
        afd.FillBuffer(reinterpret_cast<uint8_t*>(buf), stride);

        if(p_cc)
        {
            result = vanc->GetBufferForVerticalBlankingLine(ancillary.captions_line, &buf);
            if (result != S_OK) {
                msg_Err(p_stream, "Failed to get VBI line %u:0x%" PRIHR, ancillary.captions_line, result);
                goto error;
            }
            sdi::Captions captions(p_cc->p_buffer, p_cc->i_buffer, timescale, frameduration);
            captions.FillBuffer(reinterpret_cast<uint8_t*>(buf), stride);
        }

        sdi::V210::Convert(picture, stride, frame_bytes);

        result = pDLVideoFrame->SetAncillaryData(vanc);
        vanc->Release();
        if (result != S_OK) {
            msg_Err(p_stream, "Failed to set vanc:0x%" PRIHR, result);
            goto error;
        }
    }
    else for(int y = 0; y < h; ++y) {
        uint8_t *dst = (uint8_t *)frame_bytes + stride * y;
        const uint8_t *src = (const uint8_t *)picture->p[0].p_pixels +
                picture->p[0].i_pitch * y;
        memcpy(dst, src, w * 2 /* bpp */);
    }


    // compute frame duration in CLOCK_FREQ units
    length = (frameduration * CLOCK_FREQ) / timescale;
    picture->date -= clock.offset;
    scheduleTime = picture->date + DECKLINK_SCHED_OFFSET;
    result = p_output->ScheduleVideoFrame(pDLVideoFrame, scheduleTime, length, CLOCK_FREQ);
    if (result != S_OK) {
        msg_Err(p_stream, "Dropped Video frame %" PRId64 ":0x%" PRIHR,
                picture->date, result);
        goto error;
    }
    lasttimestamp = std::max(scheduleTime, lasttimestamp);

    if(!b_running) /* preroll */
    {
        if(streamStartTime == VLC_TICK_INVALID ||
           picture->date < streamStartTime)
            streamStartTime = picture->date;
    }

end:
    ret = VLC_SUCCESS;

error:
    if(p_cc)
        block_Release(p_cc);

    picture_Release(picture);
    if (pDLVideoFrame)
        pDLVideoFrame->Release();

    return ret;
}

void DBMSDIOutput::checkClockDrift()
{
    BMDTimeValue hardwareTime, timeInFrame, ticksPerFrame;
    if(!b_running || FAKE_DRIVER)
        return;
    if(S_OK == p_output->GetHardwareReferenceClock(CLOCK_FREQ,
                                                   &hardwareTime,
                                                   &timeInFrame,
                                                   &ticksPerFrame))
    {
        if(clock.system_reference == VLC_TICK_INVALID)
        {
            clock.system_reference = vlc_tick_now();
            clock.hardware_reference = hardwareTime;
        }
        else
        {
            vlc_tick_t elapsed_system = vlc_tick_now() - clock.system_reference;
            BMDTimeValue elapsed_hardware = hardwareTime - clock.hardware_reference;
            if(std::abs(elapsed_system - elapsed_hardware) >
                    std::abs(clock.offset) + VLC_TICK_FROM_MS(15))
            {
                clock.offset = elapsed_system - elapsed_hardware;
                msg_Info(p_stream, "offset now %" PRId64 " ms", clock.offset / 1000);
            }
        }
    }
}

bool DBMSDIOutput::isDrained()
{
    if(b_running)
    {
        if(!videoStream->isEOS() || !videoBuffer.isEOS())
            return false;
    }

    return true;
}

Messung
CHZG
80989792

¤ Dauer der Verarbeitung: 0.5 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.