changeset 819:a6c035e7f429 libavformat

DVB subtitle decoder by (Ian Caulfield: imc25, cam ac uk)
author michael
date Sun, 17 Jul 2005 00:28:12 +0000
parents b1d7ee1c792d
children feca73904e67
files mpegts.c mpegts.h utils.c
diffstat 3 files changed, 159 insertions(+), 75 deletions(-) [+]
line wrap: on
line diff
--- a/mpegts.c	Fri Jul 15 12:50:00 2005 +0000
+++ b/mpegts.c	Sun Jul 17 00:28:12 2005 +0000
@@ -30,7 +30,10 @@
    synchronisation is lost */
 #define MAX_RESYNC_SIZE 4096
 
-static int add_pes_stream(MpegTSContext *ts, int pid, int stream_type);
+typedef struct PESContext PESContext;
+
+static PESContext* add_pes_stream(MpegTSContext *ts, int pid, int stream_type);
+static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code);
 
 enum MpegTSFilterType {
     MPEGTS_PES,
@@ -368,8 +371,13 @@
 {
     MpegTSContext *ts = opaque;
     SectionHeader h1, *h = &h1;
-    const uint8_t *p, *p_end;
-    int program_info_length, pcr_pid, pid, stream_type, desc_length;
+    PESContext *pes;
+    AVStream *st;
+    const uint8_t *p, *p_end, *desc_list_end, *desc_end;
+    int program_info_length, pcr_pid, pid, stream_type;
+    int desc_list_len, desc_len, desc_tag;
+    int comp_page, anc_page;
+    char language[4];
     
 #ifdef DEBUG_SI
     printf("PMT:\n");
@@ -399,18 +407,57 @@
     if (p >= p_end)
         return;
     for(;;) {
+        language[0] = 0;
+        st = 0;
         stream_type = get8(&p, p_end);
         if (stream_type < 0)
             break;
         pid = get16(&p, p_end) & 0x1fff;
         if (pid < 0)
             break;
-        desc_length = get16(&p, p_end) & 0xfff;
-        if (desc_length < 0)
+        desc_list_len = get16(&p, p_end) & 0xfff;
+        if (desc_list_len < 0)
+            break;
+        desc_list_end = p + desc_list_len;
+        if (desc_list_end > p_end)
             break;
-        p += desc_length;
-        if (p > p_end)
-            return;
+        for(;;) {
+            desc_tag = get8(&p, desc_list_end);
+            if (desc_tag < 0)
+                break;
+            desc_len = get8(&p, desc_list_end);
+            desc_end = p + desc_len;
+            if (desc_end > desc_list_end)
+                break;
+#ifdef DEBUG_SI
+            printf("tag: 0x%02x len=%d\n", desc_tag, desc_len);
+#endif
+            switch(desc_tag) {
+            case DVB_SUBT_DESCID:
+                if (stream_type == STREAM_TYPE_PRIVATE_DATA)
+                    stream_type = STREAM_TYPE_SUBTITLE_DVB;
+
+                language[0] = get8(&p, desc_end);
+                language[1] = get8(&p, desc_end);
+                language[2] = get8(&p, desc_end);
+                language[3] = 0;
+                get8(&p, desc_end);
+                comp_page = get16(&p, desc_end);
+                anc_page = get16(&p, desc_end);
+
+                break;
+            case 0x0a: /* ISO 639 language descriptor */
+                language[0] = get8(&p, desc_end);
+                language[1] = get8(&p, desc_end);
+                language[2] = get8(&p, desc_end);
+                language[3] = 0;
+                break;
+            default:
+                break;
+            }
+            p = desc_end;
+        }
+        p = desc_list_end;
 
 #ifdef DEBUG_SI
         printf("stream_type=%d pid=0x%x\n", stream_type, pid);
@@ -427,12 +474,28 @@
         case STREAM_TYPE_AUDIO_AAC:
         case STREAM_TYPE_AUDIO_AC3:
         case STREAM_TYPE_AUDIO_DTS:
-            add_pes_stream(ts, pid, stream_type);
+        case STREAM_TYPE_SUBTITLE_DVB:
+            pes = add_pes_stream(ts, pid, stream_type);
+            if (pes)
+                st = new_pes_av_stream(pes, 0);
             break;
         default:
             /* we ignore the other streams */
             break;
         }
+
+        if (st) {
+            if (language[0] != 0) {
+                st->language[0] = language[0];
+                st->language[1] = language[1];
+                st->language[2] = language[2];
+                st->language[3] = language[3];
+            }
+
+            if (stream_type == STREAM_TYPE_SUBTITLE_DVB) {
+                st->codec.sub_id = (anc_page << 16) | comp_page;
+            }
+        }
     }
     /* all parameters are there */
     ts->set_service_cb(ts->set_service_opaque, 0);
@@ -653,7 +716,7 @@
 #define PES_START_SIZE 9
 #define MAX_PES_HEADER_SIZE (9 + 255)
 
-typedef struct PESContext {
+struct PESContext {
     int pid;
     int stream_type;
     MpegTSContext *ts;
@@ -666,7 +729,7 @@
     int pes_header_size;
     int64_t pts, dts;
     uint8_t header[MAX_PES_HEADER_SIZE];
-} PESContext;
+};
 
 static int64_t get_pts(const uint8_t *p)
 {
@@ -687,9 +750,8 @@
 {
     PESContext *pes = opaque;
     MpegTSContext *ts = pes->ts;
-    AVStream *st;
     const uint8_t *p;
-    int len, code, codec_type, codec_id;
+    int len, code;
     
     if (is_start) {
         pes->state = MPEGTS_HEADER;
@@ -722,59 +784,7 @@
                         goto skip;
                     if (!pes->st) {
                         /* allocate stream */
-                        switch(pes->stream_type){
-                        case STREAM_TYPE_AUDIO_MPEG1:
-                        case STREAM_TYPE_AUDIO_MPEG2:
-                            codec_type = CODEC_TYPE_AUDIO;
-                            codec_id = CODEC_ID_MP3;
-                            break;
-                        case STREAM_TYPE_VIDEO_MPEG1:
-                        case STREAM_TYPE_VIDEO_MPEG2:
-                            codec_type = CODEC_TYPE_VIDEO;
-                            codec_id = CODEC_ID_MPEG2VIDEO;
-                            break;
-                        case STREAM_TYPE_VIDEO_MPEG4:
-                            codec_type = CODEC_TYPE_VIDEO;
-                            codec_id = CODEC_ID_MPEG4;
-                            break;
-                        case STREAM_TYPE_VIDEO_H264:
-                            codec_type = CODEC_TYPE_VIDEO;
-                            codec_id = CODEC_ID_H264;
-                            break;
-                        case STREAM_TYPE_AUDIO_AAC:
-                            codec_type = CODEC_TYPE_AUDIO;
-                            codec_id = CODEC_ID_AAC;
-                            break;
-                        case STREAM_TYPE_AUDIO_AC3:
-                            codec_type = CODEC_TYPE_AUDIO;
-                            codec_id = CODEC_ID_AC3;
-                            break;
-                        case STREAM_TYPE_AUDIO_DTS:
-                            codec_type = CODEC_TYPE_AUDIO;
-                            codec_id = CODEC_ID_DTS;
-                            break;
-                        default:
-                            if (code >= 0x1c0 && code <= 0x1df) {
-                                codec_type = CODEC_TYPE_AUDIO;
-                                codec_id = CODEC_ID_MP2;
-                            } else if (code == 0x1bd) {
-                                codec_type = CODEC_TYPE_AUDIO;
-                                codec_id = CODEC_ID_AC3;
-                            } else {
-                                codec_type = CODEC_TYPE_VIDEO;
-                                codec_id = CODEC_ID_MPEG1VIDEO;
-                            }
-                            break;
-                        }
-                        st = av_new_stream(pes->stream, pes->pid);
-                        if (st) {
-                            av_set_pts_info(st, 33, 1, 90000);
-                            st->priv_data = pes;
-                            st->codec.codec_type = codec_type;
-                            st->codec.codec_id = codec_id;
-                            st->need_parsing = 1;
-                            pes->st = st;
-                        }
+                        new_pes_av_stream(pes, code);
                     }
                     pes->state = MPEGTS_PESHEADER_FILL;
                     pes->total_size = (pes->header[4] << 8) | pes->header[5];
@@ -854,7 +864,73 @@
     }
 }
 
-static int add_pes_stream(MpegTSContext *ts, int pid, int stream_type)
+static AVStream* new_pes_av_stream(PESContext *pes, uint32_t code)
+{
+    AVStream *st;
+    int codec_type, codec_id;
+
+    switch(pes->stream_type){
+    case STREAM_TYPE_AUDIO_MPEG1:
+    case STREAM_TYPE_AUDIO_MPEG2:
+        codec_type = CODEC_TYPE_AUDIO;
+        codec_id = CODEC_ID_MP3;
+        break;
+    case STREAM_TYPE_VIDEO_MPEG1:
+    case STREAM_TYPE_VIDEO_MPEG2:
+        codec_type = CODEC_TYPE_VIDEO;
+        codec_id = CODEC_ID_MPEG2VIDEO;
+        break;
+    case STREAM_TYPE_VIDEO_MPEG4:
+        codec_type = CODEC_TYPE_VIDEO;
+        codec_id = CODEC_ID_MPEG4;
+        break;
+    case STREAM_TYPE_VIDEO_H264:
+        codec_type = CODEC_TYPE_VIDEO;
+        codec_id = CODEC_ID_H264;
+        break;
+    case STREAM_TYPE_AUDIO_AAC:
+        codec_type = CODEC_TYPE_AUDIO;
+        codec_id = CODEC_ID_AAC;
+        break;
+    case STREAM_TYPE_AUDIO_AC3:
+        codec_type = CODEC_TYPE_AUDIO;
+        codec_id = CODEC_ID_AC3;
+        break;
+    case STREAM_TYPE_AUDIO_DTS:
+        codec_type = CODEC_TYPE_AUDIO;
+        codec_id = CODEC_ID_DTS;
+        break;
+    case STREAM_TYPE_SUBTITLE_DVB:
+        codec_type = CODEC_TYPE_SUBTITLE;
+        codec_id = CODEC_ID_DVB_SUBTITLE;
+        break;
+    default:
+        if (code >= 0x1c0 && code <= 0x1df) {
+            codec_type = CODEC_TYPE_AUDIO;
+            codec_id = CODEC_ID_MP2;
+        } else if (code == 0x1bd) {
+            codec_type = CODEC_TYPE_AUDIO;
+            codec_id = CODEC_ID_AC3;
+        } else {
+            codec_type = CODEC_TYPE_VIDEO;
+            codec_id = CODEC_ID_MPEG1VIDEO;
+        }
+        break;
+    }
+    st = av_new_stream(pes->stream, pes->pid);
+    if (st) {
+        av_set_pts_info(st, 33, 1, 90000);
+        st->priv_data = pes;
+        st->codec.codec_type = codec_type;
+        st->codec.codec_id = codec_id;
+        st->need_parsing = 1;
+        pes->st = st;
+    }
+    return st;
+}
+
+
+static PESContext *add_pes_stream(MpegTSContext *ts, int pid, int stream_type)
 {
     MpegTSFilter *tss;
     PESContext *pes;
@@ -862,7 +938,7 @@
     /* if no pid found, then add a pid context */
     pes = av_mallocz(sizeof(PESContext));
     if (!pes)
-        return -1;
+        return 0;
     pes->ts = ts;
     pes->stream = ts->stream;
     pes->pid = pid;
@@ -870,9 +946,9 @@
     tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes);
     if (!tss) {
         av_free(pes);
-        return -1;
+        return 0;
     }
-    return 0;
+    return pes;
 }
 
 /* handle one TS packet */
@@ -1131,11 +1207,11 @@
             }
             
             if (ts->nb_services <= 0) {
-		/* raw transport stream */
-		ts->auto_guess = 1;
-		s->ctx_flags |= AVFMTCTX_NOHEADER;
-		goto do_pcr;
-	    }
+                /* raw transport stream */
+                ts->auto_guess = 1;
+                s->ctx_flags |= AVFMTCTX_NOHEADER;
+                goto do_pcr;
+            }
             
             /* tune to first service found */
             for(i=0; i<ts->nb_services && ts->set_service_ret; i++){
--- a/mpegts.h	Fri Jul 15 12:50:00 2005 +0000
+++ b/mpegts.h	Sun Jul 17 00:28:12 2005 +0000
@@ -31,6 +31,9 @@
 #define PMT_TID   0x02 
 #define SDT_TID   0x42
 
+/* descriptor ids */
+#define DVB_SUBT_DESCID             0x59
+
 #define STREAM_TYPE_VIDEO_MPEG1     0x01
 #define STREAM_TYPE_VIDEO_MPEG2     0x02
 #define STREAM_TYPE_AUDIO_MPEG1     0x03
@@ -44,6 +47,8 @@
 #define STREAM_TYPE_AUDIO_AC3       0x81
 #define STREAM_TYPE_AUDIO_DTS       0x8a
 
+#define STREAM_TYPE_SUBTITLE_DVB    0x100
+
 unsigned int mpegts_crc32(const uint8_t *data, int len);
 extern AVOutputFormat mpegts_mux;
 
--- a/utils.c	Fri Jul 15 12:50:00 2005 +0000
+++ b/utils.c	Sun Jul 17 00:28:12 2005 +0000
@@ -2508,6 +2508,9 @@
         if (flags & AVFMT_SHOW_IDS) {
             av_log(NULL, AV_LOG_INFO, "[0x%x]", st->id);
         }
+        if (strlen(st->language) > 0) {
+            av_log(NULL, AV_LOG_INFO, "(%s)", st->language);
+        }
         av_log(NULL, AV_LOG_INFO, ": %s\n", buf);
     }
 }