Commit cc0916bf authored by Marton Balint's avatar Marton Balint

avdevice/decklink_dec: add support for decoding teletext from 10bit ancillary data

This also add supports for 4K DeckLink cards because they always output the
ancillary data in 10-bit.

v2:
- only try teletext decoding for 576i PAL mode
- some comments as requested by Aaron Levinson
Signed-off-by: 's avatarMarton Balint <cus@passwd.hu>
parent 4c1aac89
...@@ -250,8 +250,8 @@ specifically lines 6 to 22, and lines 318 to 335. Line 6 is the LSB in the mask. ...@@ -250,8 +250,8 @@ specifically lines 6 to 22, and lines 318 to 335. Line 6 is the LSB in the mask.
Selected lines which do not contain teletext information will be ignored. You Selected lines which do not contain teletext information will be ignored. You
can use the special @option{all} constant to select all possible lines, or can use the special @option{all} constant to select all possible lines, or
@option{standard} to skip lines 6, 318 and 319, which are not compatible with all @option{standard} to skip lines 6, 318 and 319, which are not compatible with all
receivers. Capturing teletext only works for SD PAL sources in 8 bit mode. receivers. Capturing teletext only works for SD PAL sources. To use this
To use this option, ffmpeg needs to be compiled with @code{--enable-libzvbi}. option, ffmpeg needs to be compiled with @code{--enable-libzvbi}.
@item channels @item channels
Defines number of audio channels to capture. Must be @samp{2}, @samp{8} or @samp{16}. Defines number of audio channels to capture. Must be @samp{2}, @samp{8} or @samp{16}.
......
...@@ -30,6 +30,7 @@ extern "C" { ...@@ -30,6 +30,7 @@ extern "C" {
extern "C" { extern "C" {
#include "config.h" #include "config.h"
#include "libavformat/avformat.h" #include "libavformat/avformat.h"
#include "libavutil/avassert.h"
#include "libavutil/avutil.h" #include "libavutil/avutil.h"
#include "libavutil/common.h" #include "libavutil/common.h"
#include "libavutil/imgutils.h" #include "libavutil/imgutils.h"
...@@ -54,21 +55,43 @@ static uint8_t calc_parity_and_line_offset(int line) ...@@ -54,21 +55,43 @@ static uint8_t calc_parity_and_line_offset(int line)
return ret; return ret;
} }
int teletext_data_unit_from_vbi_data(int line, uint8_t *src, uint8_t *tgt) static void fill_data_unit_head(int line, uint8_t *tgt)
{
tgt[0] = 0x02; // data_unit_id
tgt[1] = 0x2c; // data_unit_length
tgt[2] = calc_parity_and_line_offset(line); // field_parity, line_offset
tgt[3] = 0xe4; // framing code
}
static uint8_t* teletext_data_unit_from_vbi_data(int line, uint8_t *src, uint8_t *tgt, vbi_pixfmt fmt)
{ {
vbi_bit_slicer slicer; vbi_bit_slicer slicer;
vbi_bit_slicer_init(&slicer, 720, 13500000, 6937500, 6937500, 0x00aaaae4, 0xffff, 18, 6, 42 * 8, VBI_MODULATION_NRZ_MSB, VBI_PIXFMT_UYVY); vbi_bit_slicer_init(&slicer, 720, 13500000, 6937500, 6937500, 0x00aaaae4, 0xffff, 18, 6, 42 * 8, VBI_MODULATION_NRZ_MSB, fmt);
if (vbi_bit_slice(&slicer, src, tgt + 4) == FALSE) if (vbi_bit_slice(&slicer, src, tgt + 4) == FALSE)
return -1; return tgt;
tgt[0] = 0x02; // data_unit_id fill_data_unit_head(line, tgt);
tgt[1] = 0x2c; // data_unit_length
tgt[2] = calc_parity_and_line_offset(line); // field_parity, line_offset
tgt[3] = 0xe4; // framing code
return 0; return tgt + 46;
}
static uint8_t* teletext_data_unit_from_vbi_data_10bit(int line, uint8_t *src, uint8_t *tgt)
{
uint8_t y[720];
uint8_t *py = y;
uint8_t *pend = y + 720;
/* The 10-bit VBI data is packed in V210, but libzvbi only supports 8-bit,
* so we extract the 8 MSBs of the luma component, that is enough for
* teletext bit slicing. */
while (py < pend) {
*py++ = (src[1] >> 4) + ((src[2] & 15) << 4);
*py++ = (src[4] >> 2) + ((src[5] & 3 ) << 6);
*py++ = (src[6] >> 6) + ((src[7] & 63) << 2);
src += 8;
}
return teletext_data_unit_from_vbi_data(line, y, tgt, VBI_PIXFMT_YUV420);
} }
#endif #endif
...@@ -359,7 +382,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( ...@@ -359,7 +382,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
//fprintf(stderr,"Video Frame size %d ts %d\n", pkt.size, pkt.pts); //fprintf(stderr,"Video Frame size %d ts %d\n", pkt.size, pkt.pts);
#if CONFIG_LIBZVBI #if CONFIG_LIBZVBI
if (!no_video && ctx->teletext_lines && videoFrame->GetPixelFormat() == bmdFormat8BitYUV && videoFrame->GetWidth() == 720) { if (!no_video && ctx->teletext_lines) {
IDeckLinkVideoFrameAncillary *vanc; IDeckLinkVideoFrameAncillary *vanc;
AVPacket txt_pkt; AVPacket txt_pkt;
uint8_t txt_buf0[1611]; // max 35 * 46 bytes decoded teletext lines + 1 byte data_identifier uint8_t txt_buf0[1611]; // max 35 * 46 bytes decoded teletext lines + 1 byte data_identifier
...@@ -368,16 +391,22 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( ...@@ -368,16 +391,22 @@ HRESULT decklink_input_callback::VideoInputFrameArrived(
if (videoFrame->GetAncillaryData(&vanc) == S_OK) { if (videoFrame->GetAncillaryData(&vanc) == S_OK) {
int i; int i;
int64_t line_mask = 1; int64_t line_mask = 1;
BMDPixelFormat vanc_format = vanc->GetPixelFormat();
txt_buf[0] = 0x10; // data_identifier - EBU_data txt_buf[0] = 0x10; // data_identifier - EBU_data
txt_buf++; txt_buf++;
for (i = 6; i < 336; i++, line_mask <<= 1) { if (ctx->bmd_mode == bmdModePAL && (vanc_format == bmdFormat8BitYUV || vanc_format == bmdFormat10BitYUV)) {
uint8_t *buf; av_assert0(videoFrame->GetWidth() == 720);
if ((ctx->teletext_lines & line_mask) && vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) == S_OK) { for (i = 6; i < 336; i++, line_mask <<= 1) {
if (teletext_data_unit_from_vbi_data(i, buf, txt_buf) >= 0) uint8_t *buf;
txt_buf += 46; 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;
} }
if (i == 22)
i = 317;
} }
vanc->Release(); vanc->Release();
if (txt_buf - txt_buf0 > 1) { if (txt_buf - txt_buf0 > 1) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment