1370 lines · 48.7 KB · C++
RawDownload
        uint8_t *data = nullptr;        uint32_t size = 0;         if (packet->GetDID() == KLV_DID && packet->GetSDID() == KLV_IN_VANC_SDID) {             av_log(avctx, AV_LOG_DEBUG, "Found KLV VANC packet on line: %d\n", packet->GetLineNumber());             if (packet->GetBytes(bmdAncillaryPacketFormatUInt8, (const void**) &data, &size) == S_OK) {                // MID and PSC                if (size > 3) {                    uint8_t mid = data[0];                    uint16_t psc = data[1] << 8 | data[2];                     av_log(avctx, AV_LOG_DEBUG, "KLV with MID: %d and PSC: %d\n", mid, psc);                     auto& list = klv_packets[mid];                    uint16_t expected_psc = list.size() + 1;                     if (psc == expected_psc) {                        uint32_t data_len = size - 3;                        total_size += data_len;                         KLVPacket packet{ psc };                        packet.data.resize(data_len);                        memcpy(packet.data.data(), data + 3, data_len);                         list.push_back(std::move(packet));                    } else {                        av_log(avctx, AV_LOG_WARNING, "Out of order PSC: %d for MID: %d\n", psc, mid);                         if (!list.empty()) {                            for (auto& klv : list)                                total_size -= klv.data.size();                             list.clear();                        }                    }                }            }        }         packet->Release();    }     it->Release();    packets->Release();     if (total_size > 0) {        std::vector<uint8_t> klv;        klv.reserve(total_size);         for (size_t i = 0; i < klv_packets.size(); ++i) {            auto& list = klv_packets[i];             if (list.empty())                continue;             av_log(avctx, AV_LOG_DEBUG, "Joining MID: %d\n", (int)i);             for (auto& packet : list)                klv.insert(klv.end(), packet.data.begin(), packet.data.end());        }         AVPacket klv_packet = { 0 };        klv_packet.pts = pts;        klv_packet.dts = pts;        klv_packet.flags |= AV_PKT_FLAG_KEY;        klv_packet.stream_index = ctx->klv_st->index;        klv_packet.data = klv.data();        klv_packet.size = klv.size();         if (ff_decklink_packet_queue_put(&ctx->queue, &klv_packet) < 0) {            ++ctx->dropped;        }    }} class decklink_input_callback : public IDeckLinkInputCallback{public:        explicit decklink_input_callback(AVFormatContext *_avctx);        ~decklink_input_callback();         virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }        virtual ULONG STDMETHODCALLTYPE AddRef(void);        virtual ULONG STDMETHODCALLTYPE  Release(void);        virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags);        virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*); private:        std::atomic<int>  _refs;        AVFormatContext *avctx;        decklink_ctx    *ctx;        int no_video;        int64_t initial_video_pts;        int64_t initial_audio_pts;        IDeckLinkVideoInputFrame* last_video_frame;}; decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _refs(1){    avctx = _avctx;    decklink_cctx       *cctx = (struct decklink_cctx *)avctx->priv_data;    ctx = (struct decklink_ctx *)cctx->ctx;    no_video = 0;    initial_audio_pts = initial_video_pts = AV_NOPTS_VALUE;    last_video_frame = nullptr;} decklink_input_callback::~decklink_input_callback(){    if (last_video_frame)        last_video_frame->Release();} ULONG decklink_input_callback::AddRef(void){    return ++_refs;} ULONG decklink_input_callback::Release(void){    int ret = --_refs;    if (!ret)        delete this;    return ret;} static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame,                           IDeckLinkAudioInputPacket *audioFrame,                           int64_t wallclock,                           int64_t abs_wallclock,                           DecklinkPtsSource pts_src,                           AVRational time_base, int64_t *initial_pts,                           int copyts){    int64_t pts = AV_NOPTS_VALUE;    BMDTimeValue bmd_pts;    BMDTimeValue bmd_duration;    HRESULT res = E_INVALIDARG;    switch (pts_src) {        case PTS_SRC_AUDIO:            if (audioFrame)                res = audioFrame->GetPacketTime(&bmd_pts, time_base.den);            break;        case PTS_SRC_VIDEO:            if (videoFrame)                res = videoFrame->GetStreamTime(&bmd_pts, &bmd_duration, time_base.den);            break;        case PTS_SRC_REFERENCE:            if (videoFrame)                res = videoFrame->GetHardwareReferenceTimestamp(time_base.den, &bmd_pts, &bmd_duration);            break;        case PTS_SRC_WALLCLOCK:            /* fall through */        case PTS_SRC_ABS_WALLCLOCK:        {            /* MSVC does not support compound literals like AV_TIME_BASE_Q             * in C++ code (compiler error C4576) */            AVRational timebase;            timebase.num = 1;            timebase.den = AV_TIME_BASE;            if (pts_src == PTS_SRC_WALLCLOCK)                pts = av_rescale_q(wallclock, timebase, time_base);            else                pts = av_rescale_q(abs_wallclock, timebase, time_base);            break;        }    }    if (res == S_OK)        pts = bmd_pts / time_base.num;     if (!copyts) {        if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE)            *initial_pts = pts;        if (*initial_pts != AV_NOPTS_VALUE)            pts -= *initial_pts;    }     return pts;} static int get_bmd_timecode(AVFormatContext *avctx, AVTimecode *tc, AVRational frame_rate, BMDTimecodeFormat tc_format, IDeckLinkVideoInputFrame *videoFrame){    IDeckLinkTimecode *timecode;    int ret = AVERROR(ENOENT);#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000    int hfr = (tc_format == bmdTimecodeRP188HighFrameRate);#else    int hfr = 0;#endif    if (videoFrame->GetTimecode(tc_format, &timecode) == S_OK) {        uint8_t hh, mm, ss, ff;        if (timecode->GetComponents(&hh, &mm, &ss, &ff) == S_OK) {            int flags = (timecode->GetFlags() & bmdTimecodeIsDropFrame) ? AV_TIMECODE_FLAG_DROPFRAME : 0;            if (!hfr && av_cmp_q(frame_rate, av_make_q(30, 1)) == 1)                ff = ff << 1 | !!(timecode->GetFlags() & bmdTimecodeFieldMark);            ret = av_timecode_init_from_components(tc, frame_rate, flags, hh, mm, ss, ff, avctx);        }        timecode->Release();    }    return ret;} static int get_frame_timecode(AVFormatContext *avctx, decklink_ctx *ctx, AVTimecode *tc, IDeckLinkVideoInputFrame *videoFrame){    AVRational frame_rate = ctx->video_st->r_frame_rate;    int ret;    /* 50/60 fps content has alternating VITC1 and VITC2 timecode (see SMPTE ST     * 12-2, section 7), so the native ordering of RP188Any (HFR, VITC1, LTC,     * VITC2) would not work because LTC might not contain the field flag.     * Therefore we query the types manually. */    if (ctx->tc_format == bmdTimecodeRP188Any && av_cmp_q(frame_rate, av_make_q(30, 1)) == 1) {#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000       ret = get_bmd_timecode(avctx, tc, frame_rate, bmdTimecodeRP188HighFrameRate, videoFrame);       if (ret == AVERROR(ENOENT))#endif           ret = get_bmd_timecode(avctx, tc, frame_rate, bmdTimecodeRP188VITC1, videoFrame);       if (ret == AVERROR(ENOENT))           ret = get_bmd_timecode(avctx, tc, frame_rate, bmdTimecodeRP188VITC2, videoFrame);       if (ret == AVERROR(ENOENT))           ret = get_bmd_timecode(avctx, tc, frame_rate, bmdTimecodeRP188LTC, videoFrame);    } else {       ret = get_bmd_timecode(avctx, tc, frame_rate, ctx->tc_format, videoFrame);    }    return ret;} HRESULT decklink_input_callback::VideoInputFrameArrived(    IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioFrame){    void *frameBytes;    void *audioFrameBytes;    BMDTimeValue frameTime;    BMDTimeValue frameDuration;    int64_t wallclock = 0, abs_wallclock = 0;    int64_t video_pkt_pts, audio_pkt_pts;    struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;     if (ctx->autodetect) {        if (videoFrame && !(videoFrame->GetFlags() & bmdFrameHasNoInputSource) &&            ctx->bmd_mode == bmdModeUnknown)        {            ctx->bmd_mode = AUTODETECT_DEFAULT_MODE;        }        return S_OK;    }     // Drop the frames till system's timestamp aligns with the configured value.    if (0 == ctx->frameCount && cctx->timestamp_align) {        AVRational remainder = av_make_q(av_gettime() % cctx->timestamp_align, 1000000);        AVRational frame_duration = av_inv_q(ctx->video_st->r_frame_rate);        if (av_cmp_q(remainder, frame_duration) > 0) {            ++ctx->dropped;            return S_OK;        }    }     ctx->frameCount++;    if (ctx->audio_pts_source == PTS_SRC_WALLCLOCK || ctx->video_pts_source == PTS_SRC_WALLCLOCK)        wallclock = av_gettime_relative();    if (ctx->audio_pts_source == PTS_SRC_ABS_WALLCLOCK || ctx->video_pts_source == PTS_SRC_ABS_WALLCLOCK)        abs_wallclock = av_gettime();    video_pkt_pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts, cctx->copyts);    audio_pkt_pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts, cctx->copyts);     // Handle Video Frame    if (videoFrame) {        AVPacket pkt = { 0 };        if (ctx->frameCount % 25 == 0) {            unsigned long long qsize = ff_decklink_packet_queue_size(&ctx->queue);            av_log(avctx, AV_LOG_DEBUG,                    "Frame received (#%lu) - Valid (%liB) - QSize %fMB\n",                    ctx->frameCount,                    videoFrame->GetRowBytes() * videoFrame->GetHeight(),                    (double)qsize / 1024 / 1024);        }         videoFrame->GetBytes(&frameBytes);        videoFrame->GetStreamTime(&frameTime, &frameDuration,                                  ctx->video_st->time_base.den);         if (videoFrame->GetFlags() & bmdFrameHasNoInputSource) {            if (ctx->signal_loss_action == SIGNAL_LOSS_BARS && videoFrame->GetPixelFormat() == bmdFormat8BitYUV) {                unsigned bars[8] = {                    0xEA80EA80, 0xD292D210, 0xA910A9A5, 0x90229035,                    0x6ADD6ACA, 0x51EF515A, 0x286D28EF, 0x10801080 };                int width  = videoFrame->GetWidth();                int height = videoFrame->GetHeight();                unsigned *p = (unsigned *)frameBytes;                 for (int y = 0; y < height; y++) {                    for (int x = 0; x < width; x += 2)                        *p++ = bars[(x * 8) / width];                }            } else if (ctx->signal_loss_action == SIGNAL_LOSS_REPEAT && last_video_frame) {                videoFrame = last_video_frame;                videoFrame->GetBytes(&frameBytes);            }             if (!no_video) {                av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - No input signal detected "                        "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped);            }            no_video = 1;        } else {            if (ctx->signal_loss_action == SIGNAL_LOSS_REPEAT) {                if (last_video_frame)                    last_video_frame->Release();                last_video_frame = videoFrame;                last_video_frame->AddRef();            }            if (no_video) {                av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - Input returned "                        "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped);            }            no_video = 0;             // Handle Timecode (if requested)            if (ctx->tc_format) {                AVTimecode tcr;                if (get_frame_timecode(avctx, ctx, &tcr, videoFrame) >= 0) {                    char tcstr[AV_TIMECODE_STR_SIZE];                    const char *tc = av_timecode_make_string(&tcr, tcstr, 0);                    if (tc) {                        AVDictionary* metadata_dict = NULL;                        uint8_t* packed_metadata;                         if (av_cmp_q(ctx->video_st->r_frame_rate, av_make_q(60, 1)) < 1) {                            uint32_t tc_data = av_timecode_get_smpte_from_framenum(&tcr, 0);                            int size = sizeof(uint32_t) * 4;                            uint32_t *sd = (uint32_t *)av_packet_new_side_data(&pkt, AV_PKT_DATA_S12M_TIMECODE, size);                             if (sd) {                                *sd       = 1;       // one TC                                *(sd + 1) = tc_data; // TC                            }                        }                         if (av_dict_set(&metadata_dict, "timecode", tc, 0) >= 0) {                            size_t metadata_len;                            packed_metadata = av_packet_pack_dictionary(metadata_dict, &metadata_len);                            av_dict_free(&metadata_dict);                            if (packed_metadata) {                                if (av_packet_add_side_data(&pkt, AV_PKT_DATA_STRINGS_METADATA, packed_metadata, metadata_len) < 0)                                    av_freep(&packed_metadata);                                else if (!ctx->tc_seen)                                    ctx->tc_seen = ctx->frameCount;                            }                        }                    }                } else {                    av_log(avctx, AV_LOG_DEBUG, "Unable to find timecode.\n");                }            }        }         if (ctx->tc_format && cctx->wait_for_tc && !ctx->tc_seen) {             av_log(avctx, AV_LOG_WARNING, "No TC detected yet. wait_for_tc set. Dropping. \n");            av_log(avctx, AV_LOG_WARNING, "Frame received (#%lu) - "                        "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped);            return S_OK;        }         pkt.pts = video_pkt_pts;        pkt.dts = pkt.pts;         pkt.duration = frameDuration;        //To be made sure it still applies        pkt.flags       |= AV_PKT_FLAG_KEY;        pkt.stream_index = ctx->video_st->index;        pkt.data         = (uint8_t *)frameBytes;        pkt.size         = videoFrame->GetRowBytes() *                           videoFrame->GetHeight();        //fprintf(stderr,"Video Frame size %d ts %d\n", pkt.size, pkt.pts);         if (!no_video) {            IDeckLinkVideoFrameAncillary *vanc;            AVPacket txt_pkt = { 0 };            uint8_t txt_buf0[3531]; // 35 * 46 bytes decoded teletext lines + 1 byte data_identifier + 1920 bytes OP47 decode buffer            uint8_t *txt_buf = txt_buf0;             if (ctx->enable_klv) {                handle_klv(avctx, ctx, videoFrame, pkt.pts);            }             if (videoFrame->GetAncillaryData(&vanc) == S_OK) {                int i;                BMDPixelFormat vanc_format = vanc->GetPixelFormat();                txt_buf[0] = 0x10;    // data_identifier - EBU_data                txt_buf++;#if CONFIG_LIBZVBI                if (ctx->bmd_mode == bmdModePAL && ctx->teletext_lines &&                    (vanc_format == bmdFormat8BitYUV || vanc_format == bmdFormat10BitYUV)) {                    int64_t line_mask = 1;                    av_assert0(videoFrame->GetWidth() == 720);                    for (i = 6; i < 336; i++, line_mask <<= 1) {                        uint8_t *buf;                        if ((ctx->teletext_lines & line_mask) && vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) == S_OK) {                            if (vanc_format == bmdFormat8BitYUV)                                txt_buf = teletext_data_unit_from_vbi_data(i, buf, txt_buf, VBI_PIXFMT_UYVY);                            else                                txt_buf = teletext_data_unit_from_vbi_data_10bit(i, buf, txt_buf);                        }                        if (i == 22)                            i = 317;                    }                }#endif                if (vanc_format == bmdFormat10BitYUV && videoFrame->GetWidth() <= MAX_WIDTH_VANC) {                    int idx = get_vanc_line_idx(ctx->bmd_mode);                    for (i = vanc_line_numbers[idx].vanc_start; i <= vanc_line_numbers[idx].vanc_end; i++) {                        uint8_t *buf;                        if (vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) == S_OK) {                            uint16_t vanc[MAX_WIDTH_VANC];                            size_t vanc_size = videoFrame->GetWidth();                            if (ctx->bmd_mode == bmdModeNTSC && videoFrame->GetWidth() * 2 <= MAX_WIDTH_VANC) {                                vanc_size = vanc_size * 2;                                unpack_v210(vanc, buf, videoFrame->GetWidth());                            } else {                                extract_luma_from_v210(vanc, buf, videoFrame->GetWidth());                            }                            txt_buf = get_metadata(avctx, vanc, vanc_size,                                                   txt_buf, sizeof(txt_buf0) - (txt_buf - txt_buf0), &pkt);                        }                        if (i == vanc_line_numbers[idx].field0_vanc_end)                            i = vanc_line_numbers[idx].field1_vanc_start - 1;                    }                }                vanc->Release();                if (txt_buf - txt_buf0 > 1) {                    int stuffing_units = (4 - ((45 + txt_buf - txt_buf0) / 46) % 4) % 4;                    while (stuffing_units--) {                        memset(txt_buf, 0xff, 46);                        txt_buf[1] = 0x2c; // data_unit_length                        txt_buf += 46;                    }                    txt_pkt.pts = pkt.pts;                    txt_pkt.dts = pkt.dts;                    txt_pkt.stream_index = ctx->teletext_st->index;                    txt_pkt.data = txt_buf0;                    txt_pkt.size = txt_buf - txt_buf0;                    if (ff_decklink_packet_queue_put(&ctx->queue, &txt_pkt) < 0) {                        ++ctx->dropped;                    }                }            }        }         pkt.buf = av_buffer_create(pkt.data, pkt.size, decklink_object_free, videoFrame, 0);        if (pkt.buf)            videoFrame->AddRef();         if (ff_decklink_packet_queue_put(&ctx->queue, &pkt) < 0) {            ++ctx->dropped;        }    }     // Handle Audio Frame    if (audioFrame) {        AVPacket pkt = { 0 };        BMDTimeValue audio_pts;         //hack among hacks        pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codecpar->ch_layout.nb_channels * (ctx->audio_depth / 8);        audioFrame->GetBytes(&audioFrameBytes);        audioFrame->GetPacketTime(&audio_pts, ctx->audio_st->time_base.den);        pkt.pts = audio_pkt_pts;        pkt.dts = pkt.pts;         //fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts);        pkt.flags       |= AV_PKT_FLAG_KEY;        pkt.stream_index = ctx->audio_st->index;        pkt.data         = (uint8_t *)audioFrameBytes;         if (ff_decklink_packet_queue_put(&ctx->queue, &pkt) < 0) {            ++ctx->dropped;        }    }     return S_OK;} HRESULT decklink_input_callback::VideoInputFormatChanged(    BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode,    BMDDetectedVideoInputFormatFlags formatFlags){    struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data;    ctx->bmd_mode = mode->GetDisplayMode();    // check the C context member to make sure we set both raw_format and bmd_mode with data from the same format change callback    if (!cctx->raw_format)        ctx->raw_format = (formatFlags & bmdDetectedVideoInputRGB444) ? bmdFormat8BitARGB : bmdFormat8BitYUV;    return S_OK;} static int decklink_autodetect(struct decklink_cctx *cctx) {    struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx;    DECKLINK_BOOL autodetect_supported = false;    int i; 

Lines 501–1000 of 1370. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t