Browse code

avcodec/dca_parser: improve frame end search

Parse core frame size directly when searching for frame end instead of
using value extracted from previous frame.

Account for unused bits when calculating sync word distance for 14-bit
streams to avoid alias sync detection.

Parse EXSS frame size and skip over EXSS frame to avoid alias sync
detection.

Signed-off-by: James Almer <jamrial@gmail.com>

foo86 authored on 2016/05/13 18:48:28
Showing 1 changed files
... ...
@@ -47,6 +47,14 @@ typedef struct DCAParseContext {
47 47
 #define CORE_MARKER(state)      ((state >> 16) & 0xFFFFFFFF)
48 48
 #define EXSS_MARKER(state)      (state & 0xFFFFFFFF)
49 49
 
50
+#define STATE_LE(state)     (((state & 0xFF00FF00) >> 8) | ((state & 0x00FF00FF) << 8))
51
+#define STATE_14(state)     (((state & 0x3FFF0000) >> 8) | ((state & 0x00003FFF) >> 6))
52
+
53
+#define CORE_FRAMESIZE(state)   (((state >> 4) & 0x3FFF) + 1)
54
+#define EXSS_FRAMESIZE(state)   ((state & 0x2000000000) ? \
55
+                                 ((state >>  5) & 0xFFFFF) + 1 : \
56
+                                 ((state >> 13) & 0x0FFFF) + 1)
57
+
50 58
 /**
51 59
  * Find the end of the current frame in the bitstream.
52 60
  * @return the position of the first byte of the next frame, or -1
... ...
@@ -54,12 +62,13 @@ typedef struct DCAParseContext {
54 54
 static int dca_find_frame_end(DCAParseContext *pc1, const uint8_t *buf,
55 55
                               int buf_size)
56 56
 {
57
-    int start_found, i;
57
+    int start_found, size, i;
58 58
     uint64_t state;
59 59
     ParseContext *pc = &pc1->pc;
60 60
 
61 61
     start_found = pc->frame_start_found;
62 62
     state       = pc->state64;
63
+    size        = pc1->size;
63 64
 
64 65
     i = 0;
65 66
     if (!start_found) {
... ...
@@ -80,15 +89,75 @@ static int dca_find_frame_end(DCAParseContext *pc1, const uint8_t *buf,
80 80
             }
81 81
         }
82 82
     }
83
+
83 84
     if (start_found) {
84 85
         for (; i < buf_size; i++) {
85
-            pc1->size++;
86
+            size++;
86 87
             state = (state << 8) | buf[i];
88
+
89
+            if (start_found == 1) {
90
+                switch (pc1->lastmarker) {
91
+                case DCA_SYNCWORD_CORE_BE:
92
+                    if (size == 2) {
93
+                        pc1->framesize = CORE_FRAMESIZE(state);
94
+                        start_found    = 2;
95
+                    }
96
+                    break;
97
+                case DCA_SYNCWORD_CORE_LE:
98
+                    if (size == 2) {
99
+                        pc1->framesize = CORE_FRAMESIZE(STATE_LE(state));
100
+                        start_found    = 2;
101
+                    }
102
+                    break;
103
+                case DCA_SYNCWORD_CORE_14B_BE:
104
+                    if (size == 4) {
105
+                        pc1->framesize = CORE_FRAMESIZE(STATE_14(state)) * 8 / 14 * 2;
106
+                        start_found    = 2;
107
+                    }
108
+                    break;
109
+                case DCA_SYNCWORD_CORE_14B_LE:
110
+                    if (size == 4) {
111
+                        pc1->framesize = CORE_FRAMESIZE(STATE_14(STATE_LE(state))) * 8 / 14 * 2;
112
+                        start_found    = 2;
113
+                    }
114
+                    break;
115
+                case DCA_SYNCWORD_SUBSTREAM:
116
+                    if (size == 6) {
117
+                        pc1->framesize = EXSS_FRAMESIZE(state);
118
+                        start_found    = 2;
119
+                    }
120
+                    break;
121
+                default:
122
+                    av_assert0(0);
123
+                }
124
+                continue;
125
+            }
126
+
127
+            if (pc1->lastmarker == DCA_SYNCWORD_CORE_BE) {
128
+                if (pc1->framesize > size + 2)
129
+                    continue;
130
+
131
+                if (start_found == 2 && IS_EXSS_MARKER(state)) {
132
+                    pc1->framesize = size + 2;
133
+                    start_found    = 3;
134
+                    continue;
135
+                }
136
+
137
+                if (start_found == 3) {
138
+                    if (size == pc1->framesize + 4) {
139
+                        pc1->framesize += EXSS_FRAMESIZE(state);
140
+                        start_found     = 4;
141
+                    }
142
+                    continue;
143
+                }
144
+            }
145
+
146
+            if (pc1->framesize > size)
147
+                continue;
148
+
87 149
             if (IS_MARKER(state) &&
88 150
                 (pc1->lastmarker == CORE_MARKER(state) ||
89 151
                  pc1->lastmarker == DCA_SYNCWORD_SUBSTREAM)) {
90
-                if (pc1->framesize > pc1->size)
91
-                    continue;
92 152
                 pc->frame_start_found = 0;
93 153
                 pc->state64           = -1;
94 154
                 pc1->size             = 0;
... ...
@@ -96,8 +165,10 @@ static int dca_find_frame_end(DCAParseContext *pc1, const uint8_t *buf,
96 96
             }
97 97
         }
98 98
     }
99
+
99 100
     pc->frame_start_found = start_found;
100 101
     pc->state64           = state;
102
+    pc1->size             = size;
101 103
     return END_NOT_FOUND;
102 104
 }
103 105
 
... ...
@@ -110,11 +181,11 @@ static av_cold int dca_parse_init(AVCodecParserContext *s)
110 110
 }
111 111
 
112 112
 static int dca_parse_params(const uint8_t *buf, int buf_size, int *duration,
113
-                            int *sample_rate, int *framesize)
113
+                            int *sample_rate)
114 114
 {
115 115
     GetBitContext gb;
116 116
     uint8_t hdr[12 + AV_INPUT_BUFFER_PADDING_SIZE] = { 0 };
117
-    int ret, sample_blocks, sr_code;
117
+    int ret, sample_blocks;
118 118
 
119 119
     if (buf_size < 12)
120 120
         return AVERROR_INVALIDDATA;
... ...
@@ -130,13 +201,8 @@ static int dca_parse_params(const uint8_t *buf, int buf_size, int *duration,
130 130
         return AVERROR_INVALIDDATA;
131 131
     *duration = 256 * (sample_blocks / 8);
132 132
 
133
-    *framesize = get_bits(&gb, 14) + 1;
134
-    if (*framesize < 95)
135
-        return AVERROR_INVALIDDATA;
136
-
137
-    skip_bits(&gb, 6);
138
-    sr_code      = get_bits(&gb, 4);
139
-    *sample_rate = avpriv_dca_sample_rates[sr_code];
133
+    skip_bits(&gb, 20);
134
+    *sample_rate = avpriv_dca_sample_rates[get_bits(&gb, 4)];
140 135
     if (*sample_rate == 0)
141 136
         return AVERROR_INVALIDDATA;
142 137
 
... ...
@@ -164,7 +230,7 @@ static int dca_parse(AVCodecParserContext *s, AVCodecContext *avctx,
164 164
     }
165 165
 
166 166
     /* read the duration and sample rate from the frame header */
167
-    if (!dca_parse_params(buf, buf_size, &duration, &sample_rate, &pc1->framesize)) {
167
+    if (!dca_parse_params(buf, buf_size, &duration, &sample_rate)) {
168 168
         if (!avctx->sample_rate)
169 169
             avctx->sample_rate = sample_rate;
170 170
         s->duration = av_rescale(duration, avctx->sample_rate, sample_rate);