summaryrefslogtreecommitdiff
path: root/libavcodec/libzvbi-teletextdec.c
diff options
context:
space:
mode:
authorMarton Balint <cus@passwd.hu>2014-03-01 02:10:15 +0100
committerMarton Balint <cus@passwd.hu>2014-03-08 21:58:12 +0100
commit085ca7dcdbf9ab6c23e3a5397b1f6d4aa23f763d (patch)
treeb59e2a015d377716d6a7ea8a23d20ae234fffa62 /libavcodec/libzvbi-teletextdec.c
parentae017c26325ff8f3d8ebdcd5951d03f92c28147f (diff)
libzvbi-teletextdec: split dvb packet to slices
Instead of using the demux function of libzvbi to split the packet to slices (vbi lines), lets do it ourselves. - eliminates the 1 frame delay between page input and output - handles non-ascending line numbers more gracefully - enables us to return error codes on some invalid packets instead of silently ignoring them Signed-off-by: Marton Balint <cus@passwd.hu>
Diffstat (limited to 'libavcodec/libzvbi-teletextdec.c')
-rw-r--r--libavcodec/libzvbi-teletextdec.c86
1 files changed, 54 insertions, 32 deletions
diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c
index 2b1be82a52..32475b18f8 100644
--- a/libavcodec/libzvbi-teletextdec.c
+++ b/libavcodec/libzvbi-teletextdec.c
@@ -37,6 +37,7 @@
#define MAX_BUFFERED_PAGES 25
#define BITMAP_CHAR_WIDTH 12
#define BITMAP_CHAR_HEIGHT 10
+#define MAX_SLICES 64
typedef struct TeletextPage
{
@@ -65,11 +66,10 @@ typedef struct TeletextContext
int handler_ret;
vbi_decoder * vbi;
- vbi_dvb_demux * dx;
#ifdef DEBUG
vbi_export * ex;
#endif
- vbi_sliced sliced[64];
+ vbi_sliced sliced[MAX_SLICES];
} TeletextContext;
static int chop_spaces_utf8(const unsigned char* t, int len)
@@ -358,15 +358,46 @@ static void handler(vbi_event *ev, void *user_data)
vbi_unref_page(&page);
}
+static inline int data_identifier_is_teletext(int data_identifier) {
+ /* See EN 301 775 section 4.4.2. */
+ return (data_identifier >= 0x10 && data_identifier <= 0x1F ||
+ data_identifier >= 0x99 && data_identifier <= 0x9B);
+}
+
+static int slice_to_vbi_lines(TeletextContext *ctx, uint8_t* buf, int size)
+{
+ int lines = 0;
+ while (size >= 2 && lines < MAX_SLICES) {
+ int data_unit_id = buf[0];
+ int data_unit_length = buf[1];
+ if (data_unit_length + 2 > size)
+ return AVERROR_INVALIDDATA;
+ if (data_unit_id == 0x02 || data_unit_id == 0x03) {
+ if (data_unit_length != 0x2c)
+ return AVERROR_INVALIDDATA;
+ else {
+ int line_offset = buf[2] & 0x1f;
+ int field_parity = buf[2] & 0x20;
+ int i;
+ ctx->sliced[lines].id = VBI_SLICED_TELETEXT_B;
+ ctx->sliced[lines].line = (line_offset > 0 ? (line_offset + (field_parity ? 0 : 313)) : 0);
+ for (i = 0; i < 42; i++)
+ ctx->sliced[lines].data[i] = vbi_rev8(buf[4 + i]);
+ lines++;
+ }
+ }
+ size -= data_unit_length + 2;
+ buf += data_unit_length + 2;
+ }
+ if (size)
+ av_log(ctx, AV_LOG_WARNING, "%d bytes remained after slicing data\n", size);
+ return lines;
+}
+
static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *pkt)
{
TeletextContext *ctx = avctx->priv_data;
AVSubtitle *sub = data;
- const uint8_t *buf = pkt->data;
- int left = pkt->size;
- uint8_t pesheader[45] = {0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x85, 0x80, 0x24, 0x21, 0x00, 0x01, 0x00, 0x01};
- int pesheader_size = sizeof(pesheader);
- const uint8_t *pesheader_buf = pesheader;
int ret = 0;
if (!ctx->vbi) {
@@ -378,40 +409,34 @@ static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *data_si
return AVERROR(ENOMEM);
}
}
- if (!ctx->dx && (!(ctx->dx = vbi_dvb_pes_demux_new (/* callback */ NULL, NULL))))
- return AVERROR(ENOMEM);
if (avctx->pkt_timebase.den && pkt->pts != AV_NOPTS_VALUE)
ctx->pts = av_rescale_q(pkt->pts, avctx->pkt_timebase, AV_TIME_BASE_Q);
- if (left) {
+ if (pkt->size) {
+ int lines;
+ const int full_pes_size = pkt->size + 45; /* PES header is 45 bytes */
+
// We allow unreasonably big packets, even if the standard only allows a max size of 1472
- if ((pesheader_size + left) < 184 || (pesheader_size + left) > 65504 || (pesheader_size + left) % 184 != 0)
+ if (full_pes_size < 184 || full_pes_size > 65504 || full_pes_size % 184 != 0)
return AVERROR_INVALIDDATA;
- memset(pesheader + 14, 0xff, pesheader_size - 14);
- AV_WB16(pesheader + 4, left + pesheader_size - 6);
-
- /* PTS is deliberately left as 0 in the PES header, otherwise libzvbi uses
- * it to detect dropped frames. Unforunatey the guessed packet PTS values
- * (see mpegts demuxer) are not accurate enough to pass that test. */
- vbi_dvb_demux_cor(ctx->dx, ctx->sliced, 64, NULL, &pesheader_buf, &pesheader_size);
-
ctx->handler_ret = pkt->size;
- while (left > 0) {
- int64_t pts = 0;
- unsigned int lines = vbi_dvb_demux_cor(ctx->dx, ctx->sliced, 64, &pts, &buf, &left);
- av_dlog(avctx, "ctx=%p buf_size=%d left=%u lines=%u pts=%f pkt_pts=%f\n",
- ctx, pkt->size, left, lines, (double)pts/90000.0, (double)pkt->pts/90000.0);
+ if (data_identifier_is_teletext(*pkt->data)) {
+ if ((lines = slice_to_vbi_lines(ctx, pkt->data + 1, pkt->size - 1)) < 0)
+ return lines;
+ av_dlog(avctx, "ctx=%p buf_size=%d lines=%u pkt_pts=%7.3f\n",
+ ctx, pkt->size, lines, (double)pkt->pts/90000.0);
if (lines > 0) {
-#ifdef DEBUGx
+#ifdef DEBUG
int i;
- for(i=0; i<lines; ++i)
- av_log(avctx, AV_LOG_DEBUG,
- "lines=%d id=%x\n", i, ctx->sliced[i].id);
+ av_log(avctx, AV_LOG_DEBUG, "line numbers:");
+ for(i = 0; i < lines; i++)
+ av_log(avctx, AV_LOG_DEBUG, " %d", ctx->sliced[i].line);
+ av_log(avctx, AV_LOG_DEBUG, "\n");
#endif
- vbi_decode(ctx->vbi, ctx->sliced, lines, (double)pts/90000.0);
+ vbi_decode(ctx->vbi, ctx->sliced, lines, 0.0);
ctx->lines_processed += lines;
}
}
@@ -474,7 +499,6 @@ static int teletext_init_decoder(AVCodecContext *avctx)
avctx->height = 25 * BITMAP_CHAR_HEIGHT;
}
- ctx->dx = NULL;
ctx->vbi = NULL;
ctx->pts = AV_NOPTS_VALUE;
@@ -497,9 +521,7 @@ static int teletext_close_decoder(AVCodecContext *avctx)
subtitle_rect_free(&ctx->pages[--ctx->nb_pages].sub_rect);
av_freep(&ctx->pages);
- vbi_dvb_demux_delete(ctx->dx);
vbi_decoder_delete(ctx->vbi);
- ctx->dx = NULL;
ctx->vbi = NULL;
ctx->pts = AV_NOPTS_VALUE;
return 0;