Project

General

Profile

Bug #1592 ยป avc.c

Modified avc.c file with fixed avc_find_startcode - Eric Valette, 2013-02-12 21:07

 
1
/*
2
 * AVC helper functions for muxers
3
 * Copyright (c) 2006 Baptiste Coudurier <[email protected]>
4
 *
5
 * This file is part of FFmpeg.
6
 *
7
 * FFmpeg is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * FFmpeg is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with FFmpeg; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
 */
21

    
22
#include "avc.h"
23

    
24
static const uint8_t *avc_find_startcode_internal(const uint8_t *p, const uint8_t *end)
25
{
26
    const uint8_t *a = p + 4 - ((intptr_t)p & 3);
27

    
28
    for (end -= 3; p < a && p < end; p++) {
29
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
30
            return p;
31
    }
32

    
33
    for (end -= 3; p < end; p += 4) {
34
        uint32_t x = *(const uint32_t*)p;
35
//      if ((x - 0x01000100) & (~x) & 0x80008000) // little endian
36
//      if ((x - 0x00010001) & (~x) & 0x00800080) // big endian
37
        if ((x - 0x01010101) & (~x) & 0x80808080) { // generic
38
            if (p[1] == 0) {
39
                if (p[0] == 0 && p[2] == 1)
40
                    return p;
41
                if (p[2] == 0 && p[3] == 1)
42
                    return p+1;
43
            }
44
            if (p[3] == 0) {
45
                if (p[2] == 0 && p[4] == 1)
46
                    return p+2;
47
                if (p[4] == 0 && p[5] == 1)
48
                    return p+3;
49
            }
50
        }
51
    }
52

    
53
    for (end += 3; p < end; p++) {
54
        if (p[0] == 0 && p[1] == 0 && p[2] == 1)
55
            return p;
56
    }
57

    
58
    return end + 3;
59
}
60

    
61
static const uint8_t *avc_find_startcode(const uint8_t *p, const uint8_t *end){
62
    const uint8_t *out= avc_find_startcode_internal(p, end);
63
    while(p<out && out<end && !out[-1]) out--;
64
    return out;
65
}
66

    
67
static int avc_parse_nal_units(sbuf_t *sb, const uint8_t *buf_in, int size)
68
{
69
    const uint8_t *p = buf_in;
70
    const uint8_t *end = p + size;
71
    const uint8_t *nal_start, *nal_end;
72

    
73
    size = 0;
74
    nal_start = avc_find_startcode(p, end);
75
    for (;;) {
76
        while (nal_start < end && !*(nal_start++));
77
        if (nal_start == end)
78
            break;
79

    
80
        nal_end = avc_find_startcode(nal_start, end);
81

    
82
	int l = nal_end - nal_start;
83

    
84
	sbuf_put_be32(sb, l);
85
	sbuf_append(sb, nal_start, l);
86
        size += 4 + l;
87
        nal_start = nal_end;
88
    }
89
    return size;
90
}
91

    
92
static int
93
avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size)
94
{
95
  sbuf_t sb;
96
  sbuf_init(&sb);
97
  avc_parse_nal_units(&sb, buf_in, *size);
98

    
99
  free(*buf);
100
  *buf = sb.sb_data;
101
  *size = sb.sb_ptr;
102
  return 0;
103
}
104

    
105

    
106
static uint32_t 
107
RB32(const uint8_t *d)
108
{
109
  return (d[0] << 24) | (d[1] << 16) | (d[2] << 8) | d[3];
110
}
111

    
112
static uint32_t 
113
RB24(const uint8_t *d)
114
{
115
  return (d[0] << 16) | (d[1] << 8) | d[2];
116
}
117

    
118
#define FFMIN(a, b) ((a) > (b) ? (b) : (a))
119

    
120
static int
121
isom_write_avcc(sbuf_t *sb, const uint8_t *data, int len)
122
{
123
  if (len > 6) {
124
    /* check for h264 start code */
125
    if (RB32(data) == 0x00000001 ||
126
	RB24(data) == 0x000001) {
127
      uint8_t *buf=NULL, *end, *start;
128
      uint32_t *sps_size_array=0, *pps_size_array=0;
129
      uint32_t pps_count=0,sps_count=0;
130
      uint8_t **sps_array=0, **pps_array=0;
131
      int i;
132

    
133
      int ret = avc_parse_nal_units_buf(data, &buf, &len);
134
      if (ret < 0)
135
	return ret;
136
      start = buf;
137
      end = buf + len;
138

    
139
      /* look for sps and pps */
140
      while (end - buf > 4) {
141
	unsigned int size;
142
	uint8_t nal_type;
143
	size = FFMIN(RB32(buf), end - buf - 4);
144
	buf += 4;
145
	nal_type = buf[0] & 0x1f;
146
	
147
	if ((nal_type == 7) && (size >= 4) && (size <= UINT16_MAX)) { /* SPS */
148
	  sps_array = realloc(sps_array,sizeof(uint8_t*)*(sps_count+1));
149
	  sps_size_array = realloc(sps_size_array,sizeof(uint32_t)*(sps_count+1));
150
	  sps_array[sps_count] = buf;
151
	  sps_size_array[sps_count] = size;
152
	  sps_count++;
153
	} else if ((nal_type == 8) && (size <= UINT16_MAX)) { /* PPS */
154
	  pps_size_array = realloc(pps_size_array,sizeof(uint32_t)*(pps_count+1));
155
	  pps_array = realloc(pps_array,sizeof (uint8_t*)*(pps_count+1));
156
	  pps_array[pps_count] = buf;
157
	  pps_size_array[pps_count] = size;
158
	  pps_count++;
159
	}
160
	buf += size;
161
      }
162
      if(!sps_count || !pps_count) {
163
	free(start);
164
	if (sps_count)
165
	  free(sps_array);
166
	if (pps_count)
167
	  free(pps_array);
168
	return -1;
169
      }
170

    
171
      sbuf_put_byte(sb, 1); /* version */
172
      sbuf_put_byte(sb, sps_array[0][1]); /* profile */
173
      sbuf_put_byte(sb, sps_array[0][2]); /* profile compat */
174
      sbuf_put_byte(sb, sps_array[0][3]); /* level */
175
      sbuf_put_byte(sb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */
176
      sbuf_put_byte(sb, 0xe0+sps_count); /* 3 bits reserved (111) + 5 bits number of sps (00001) */
177
      for (i=0;i<sps_count;i++) {
178
	sbuf_put_be16(sb, sps_size_array[i]);
179
	sbuf_append(sb, sps_array[i], sps_size_array[i]);
180
      }
181

    
182
      sbuf_put_byte(sb, pps_count); /* number of pps */
183
      for (i=0;i<pps_count;i++) {
184
	sbuf_put_be16(sb, pps_size_array[i]);
185
	sbuf_append(sb, pps_array[i], pps_size_array[i]);
186
      }
187
      free(start);
188

    
189
      if (sps_count)
190
	free(sps_array);
191
      if (pps_count)
192
	free(pps_array);
193
    } else {
194
      sbuf_append(sb, data, len);
195
    }
196
  }
197
  return 0;
198
}
199

    
200

    
201
#ifdef DUMP_SRC
202
static FILE *srcDump = NULL;
203
#endif
204

    
205
th_pkt_t *
206
avc_convert_pkt(th_pkt_t *src)
207
{
208
  th_pkt_t *pkt = malloc(sizeof(th_pkt_t));
209
  *pkt = *src;
210
  pkt->pkt_refcount = 1;
211
  pkt->pkt_header = NULL;
212
  pkt->pkt_payload = NULL;
213

    
214
#ifdef DUMP_SRC
215
  if (srcDump == NULL) {
216
    srcDump = fopen("/home/hts/dump","w");
217
  }
218
#endif  
219
  if (src->pkt_header) {
220
    sbuf_t headers;
221
    sbuf_init(&headers);
222
    
223
    isom_write_avcc(&headers, pktbuf_ptr(src->pkt_header),
224
		    pktbuf_len(src->pkt_header));
225
    pkt->pkt_header = pktbuf_make(headers.sb_data, headers.sb_ptr);
226
  }
227

    
228
  sbuf_t payload;
229
  sbuf_init(&payload);
230

    
231
  if(src->pkt_header)
232
    avc_parse_nal_units(&payload, pktbuf_ptr(src->pkt_header),
233
			pktbuf_len(src->pkt_header));
234
  
235
#ifdef DUMP_SRC
236
  size_t  size;
237
  size =  pktbuf_len(src->pkt_payload);
238
  fwrite(&size,sizeof(size),1,srcDump);
239
  fwrite(pktbuf_ptr(src->pkt_payload), pktbuf_len(src->pkt_payload), 1, srcDump);
240
  fflush (srcDump);
241
#endif  
242
  avc_parse_nal_units(&payload, pktbuf_ptr(src->pkt_payload),
243
		      pktbuf_len(src->pkt_payload));
244
  
245
  pkt->pkt_payload = pktbuf_make(payload.sb_data, payload.sb_ptr);
246
  pkt_ref_dec(src);
247
  return pkt;
248
}
249

    
    (1-1/1)