[Libav-user] MPEG1-2 CEA-608 CC (subtitle) decoding fails for interlaced content

Eric Jong ericdejong_nospam10 at gmx.net
Wed Nov 28 17:08:37 EET 2018


Here is an example:     

.ts file: https://www.dropbox.com/s/iu8qec0pcng6hv0/TestVid.ts?dl=0
Expected output is both field 1 and field 2,
but only field 2 is shown in output. When I modify the libav source I
do get field 1 and field 2 with the proper data!
 
// VERY SIMPLE EXAMPLE, NO ERROR CHECKING!
int video_stream_idx = -1;
AVPacket pkt;
AVCodecContext* video_dec_ctx = NULL;
AVFrame* frame = NULL;
int video_frame_count = 0;
char CChar(unsigned char ch) {
    ch &= 0x7F;
    return (ch < ' ') ? ' ' : ch;
}
static int decode_packet() {
    int i,j,cc_valid,cc_type, ret = 0, decoded;
    unsigned char data;
    decoded = pkt.size;
    if (pkt.stream_index == video_stream_idx) {
        avcodec_send_packet(video_dec_ctx, &pkt);
        do
        {
            if ((ret = avcodec_receive_frame(video_dec_ctx, frame)) == 0)
            {
                AVFrameSideData* side_data = frame->side_data[0];
                while (frame->nb_side_data--)
                {
                    for (i = 0; i < frame->nb_side_data; i++)
                        if (frame->side_data[i]->type == AV_FRAME_DATA_A53_CC)
                        {
                            // Expected subtitle:
                            //   CHRISTMAS.
                            //   SOMEONE THAT WOULD SIGN AWAY
                            //   THEIR RIGHTS -- ELIZABETH HAS
                            for (j = 0; j < frame->side_data[i]->size/3; j+=3)
                            {
                                data = frame->side_data[i]->data[j];
                                if ((data & 0xF8) != 0xF8)
                                    break;
                                cc_valid = data & 0x04;
                                cc_type = data & 3;
                                
                                if (cc_type >= 2)
                                    break;
                                if (cc_valid && cc_type == 0)
                                    printf("cc field 1 %c%c\n",
                                        CChar(frame->side_data[i]->data[j + 1]),
                                        CChar(frame->side_data[i]->data[j + 2]));
                                else if (cc_valid && cc_type == 1)
                                    printf("cc field 2 %c%c\n",
                                        CChar(frame->side_data[i]->data[j + 1]),
                                        CChar(frame->side_data[i]->data[j + 2]));
                            }
                        }
                }
                av_frame_unref(frame);
            }
        } while (ret == 0);
    }
    return decoded;
}
 
int main(int  argc, char*  argv[]) {
    int ret = 0, got_frame;
    AVFormatContext* fmt_ctx = NULL;
    avformat_open_input(&fmt_ctx, "Z:\\temp\\TestVid.ts", NULL, NULL);
    avformat_find_stream_info(fmt_ctx, NULL);
    video_stream_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
    video_dec_ctx = avcodec_alloc_context3(codec);
    if (avcodec_open2(video_dec_ctx, codec, NULL) < 0)
        exit(1);
    frame = av_frame_alloc();
    av_init_packet(&pkt);
    while (av_read_frame(fmt_ctx, &pkt) >= 0) {
        do {
            ret = decode_packet();
            if (ret < 0)
                break;
            pkt.data += ret;
            pkt.size -= ret;
        } while (pkt.size > 0);
        av_free_packet(&pkt);
    }
    getch();
}


More information about the Libav-user mailing list