source: titan/libeplayer3/output/writer/mipsel/h264.c @ 42162

Last change on this file since 42162 was 42162, checked in by obi, 6 years ago

update libeplayer3 to v47

File size: 14.9 KB
RevLine 
[39692]1/*
2 * linuxdvb output/writer handling.
3 *
4 * konfetti 2010 based on linuxdvb.c code from libeplayer2
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22/* ***************************** */
23/* Includes                      */
24/* ***************************** */
25
26#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29#include <unistd.h>
30#include <fcntl.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <sys/uio.h>
35#include <linux/dvb/video.h>
36#include <linux/dvb/audio.h>
37#include <memory.h>
38#include <asm/types.h>
39#include <pthread.h>
40#include <errno.h>
41#include <assert.h>
42#include <stdint.h>
43#include <poll.h>
44
45#include "stm_ioctls.h"
46#include "bcm_ioctls.h"
47
48#include "common.h"
49#include "output.h"
50#include "debug.h"
51#include "misc.h"
52#include "pes.h"
53#include "writer.h"
54
55/* ***************************** */
56/* Makros/Constants              */
57/* ***************************** */
[42162]58#define H264_SILENT
[40348]59//#define H264_DEBUG
[39692]60#ifdef H264_DEBUG
61
[40348]62static short debug_level = 0;
[39692]63
64#define h264_printf(level, fmt, x...) do { \
65if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
66#else
67#define h264_printf(level, fmt, x...)
68#endif
69
70#ifndef H264_SILENT
71#define h264_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
72#else
73#define h264_err(fmt, x...)
74#endif
75
76#define IOVEC_SIZE                                      128
77
78/* ***************************** */
79/* Types                         */
80/* ***************************** */
81
82/* ***************************** */
83/* Varaibles                     */
84/* ***************************** */
85static unsigned char           Head[] = {0, 0, 0, 1};
86static int                     initialHeader = 1;
87static unsigned int            NalLengthBytes = 1;
88static unsigned char           *CodecData     = NULL;
89static unsigned int            CodecDataLen   = 0;
[40322]90static int                     avc3 = 0;
[42162]91static int                     sps_pps_in_stream = 0;
[39692]92/* ***************************** */
93/* Prototypes                    */
94/* ***************************** */
95
96/* ***************************** */
97/* MISC Functions                */
98/* ***************************** */
[40322]99
100// Please see: https://bugzilla.mozilla.org/show_bug.cgi?id=1105771
101static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, uint8_t *pData, uint32_t dataSize)
[39692]102{
[40322]103    uint8_t *aExtraData = *ppExtraData;
104   
105    if (aExtraData[0] != 1 || !pData) {
106        // Not AVCC or nothing to update with.
107        return -1;
108    }
109   
110    int32_t nalsize = (aExtraData[4] & 3) + 1;
111   
112    uint8_t sps[256];
113    uint8_t spsIdx = 0;
114   
115    uint8_t numSps = 0;
116   
117    uint8_t pps[256];
118    uint8_t ppsIdx = 0;
119   
120    uint8_t numPps = 0;
121
122    if(nalsize != 4)
123    {
124        return -1;
125    }
126   
127    // Find SPS and PPS NALUs in AVCC data
128    uint8_t *d = pData;
129    while (d + 4 < pData + dataSize)
130    {
131        uint32_t nalLen = ReadUint32(d);
132       
133        uint8_t nalType = d[4] & 0x1f;
134        if (nalType == 7)
135        { /* SPS */
136       
137            // 16 bits size
138            sps[spsIdx++] = (uint8_t)(0xFF & (nalLen >> 8));
139            sps[spsIdx++] = (uint8_t)(0xFF & nalLen);
140           
141            if (spsIdx + nalLen >= sizeof(sps))
142            {
143                h264_err("SPS no free space to copy...\n");
144                return -1;
145            }
146            memcpy(&(sps[spsIdx]), d + 4, nalLen);
147            spsIdx += nalLen;
148           
149            numSps += 1;
150           
151            h264_printf(10, "SPS len[%u]...\n", nalLen);
152        }
153        else if (nalType == 8)
154        { /* PPS */
155
156            // 16 bits size
157            pps[ppsIdx++] = (uint8_t)(0xFF & (nalLen >> 8));
158            pps[ppsIdx++] = (uint8_t)(0xFF & nalLen);
159           
160            if (ppsIdx + nalLen >= sizeof(sps))
161            {
162                h264_err("PPS not free space to copy...\n");
163                return -1;
164            }
165            memcpy(&(pps[ppsIdx]), d + 4, nalLen);
166            ppsIdx += nalLen;
167           
168            numPps += 1;
169           
170            h264_printf(10, "PPS len[%u]...\n", nalLen);
171        }
172        d += 4 + nalLen;
173    }
174    uint32_t idx = 0;
175    *ppExtraData = malloc(7 + spsIdx + ppsIdx);
176    aExtraData = *ppExtraData;
177    aExtraData[idx++] = 0x1;            // version
178    aExtraData[idx++] = sps[3];         // profile
179    aExtraData[idx++] = sps[4];         // profile compat
180    aExtraData[idx++] = sps[5];         // level
181    aExtraData[idx++] = 0xff;           // nal size - 1
182   
183    aExtraData[idx++] = 0xe0 | numSps;
184    if (numSps)
185    {
186        memcpy(&(aExtraData[idx]), sps, spsIdx);
187        idx += spsIdx;
188    }
189   
190    aExtraData[idx++] = numPps;
191    if (numPps)
192    {
193        memcpy(&(aExtraData[idx]), pps, ppsIdx);
194        idx += ppsIdx;
195    }
196   
197    h264_printf(10, "aExtraData len[%u]...\n", idx);
198    *pExtraDataSize = idx;
199    return 0;
200}
201
202static int32_t PreparCodecData(unsigned char *data, unsigned int cd_len, unsigned int *NalLength)
203{
204    h264_printf(10, "H264 check codec data..!\n");
205    int32_t ret = -100;
[39692]206    if (data)
207    {
208        unsigned char tmp[2048];
209        unsigned int tmp_len = 0;
210
211        unsigned int cd_pos = 0;
212        h264_printf(10, "H264 have codec data..!\n");
213        if (cd_len > 7 && data[0] == 1)
214        {
215            unsigned short len = (data[6] << 8) | data[7];
216            if (cd_len >= (len + 8))
217            {
218                unsigned int i=0;
219                uint8_t profile_num[] = { 66, 77, 88, 100 };
220                uint8_t profile_cmp[2] = { 0x67, 0x00 };
221                const char *profile_str[] = { "baseline", "main", "extended", "high" };
222                memcpy(tmp, Head, sizeof(Head));
223                tmp_len += 4;
224                memcpy(tmp + tmp_len, data + 8, len);
225                for (i = 0; i < 4; ++i)
226                {
227                    profile_cmp[1] = profile_num[i];
228                    if (!memcmp(tmp+tmp_len, profile_cmp, 2))
229                    {
230                        uint8_t level_org = tmp[tmp_len + 3];
231                        if (level_org > 0x29)
232                        {
233                            h264_printf(10, "H264 %s profile@%d.%d patched down to 4.1!", profile_str[i], level_org / 10 , level_org % 10);
234                            tmp[tmp_len+3] = 0x29; // level 4.1
235                        }
236                        else
237                        {
238                            h264_printf(10, "H264 %s profile@%d.%d", profile_str[i], level_org / 10 , level_org % 10);
239                        }
240                        break;
241                    }
242                }
243                tmp_len += len;
244                cd_pos = 8 + len;
245                if (cd_len > (cd_pos + 2))
246                {
247                    len = (data[cd_pos + 1] << 8) | data[cd_pos + 2];
248                    cd_pos += 3;
249                    if (cd_len >= (cd_pos+len))
250                    {
251                        memcpy(tmp+tmp_len, "\x00\x00\x00\x01", 4);
252                        tmp_len += 4;
253                        memcpy(tmp+tmp_len, data+cd_pos, len);
254                        tmp_len += len;
255                       
256                        CodecData = malloc(tmp_len);
257                        memcpy(CodecData, tmp, tmp_len);
258                        CodecDataLen = tmp_len;
259                       
260                        *NalLength = (data[4] & 0x03) + 1;
[40322]261                        ret = 0;
[39692]262                    }
263                    else
264                    {
265                        h264_printf(10, "codec_data too short(4)");
[40322]266                        ret = -4;
[39692]267                    }
268                }
269                else
270                {
271                    h264_printf(10,  "codec_data too short(3)");
[40322]272                    ret = -3;
[39692]273                }
274            }
275            else
276            {
277                h264_printf(10, "codec_data too short(2)");
[40322]278                ret = -2;
[39692]279            }
280        }
281        else if (cd_len <= 7)
282        {
283            h264_printf(10, "codec_data too short(1)");
[40322]284            ret = -1;
[39692]285        }
286        else
287        {
288            h264_printf(10, "wrong avcC version %d!", data[0]);
289        }
290    }
291    else
292    {
293        *NalLength = 0;
294    }
[40322]295   
296    return ret;
[39692]297}
298
299static int reset()
[40322]300{
[39692]301    initialHeader = 1;
[40322]302    avc3 = 0;
[42162]303    sps_pps_in_stream = 0;
[39692]304    return 0;
305}
306
307static int writeData(void* _call)
308{
309    WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
310
311    unsigned char           PesHeader[PES_MAX_HEADER_SIZE];
312    unsigned long long int  VideoPts;
313    unsigned int            TimeDelta;
314    unsigned int            TimeScale;
315    int                     len = 0;
316    int ic = 0;
317    struct iovec iov[IOVEC_SIZE];
[40322]318    h264_printf(20, "\n");
[39692]319
320    if (call == NULL)
321    {
322        h264_err("call data is NULL...\n");
323        return 0;
324    }
325
326    TimeDelta = call->FrameRate;
327    TimeScale = call->FrameScale;
328    VideoPts  = call->Pts;
329   
[40322]330    h264_printf(20, "VideoPts %lld - %d %d\n", call->Pts, TimeDelta, TimeScale);
[39692]331
332    if ((call->data == NULL) || (call->len <= 0))
333    {
334        h264_err("NULL Data. ignoring...\n");
335        return 0;
336    }
337
338    if (call->fd < 0)
339    {
340        h264_err("file pointer < 0. ignoring ...\n");
341        return 0;
342    }
343
344    /* AnnexA */
[40322]345    if( !avc3 && ((1 < call->private_size && 0 == call->private_data[0]) ||
[39692]346        (call->len > 3) && ((call->data[0] == 0x00 && call->data[1] == 0x00 && call->data[2] == 0x00 && call->data[3] == 0x01) ||
[40322]347        (call->data[0] == 0xff && call->data[1] == 0xff && call->data[2] == 0xff && call->data[3] == 0xff))))
[39692]348    {
[42162]349        uint32_t i = 0;
350        uint8_t InsertPrivData = !sps_pps_in_stream;
[40322]351        uint32_t PacketLength = 0;
352        uint32_t FakeStartCode = (call->Version << 8) | PES_VERSION_FAKE_START_CODE;
[42162]353        iov[ic++].iov_base = PesHeader;
[39692]354       
[42162]355        while (InsertPrivData && i < 36 && (call->len - i) > 5)
[39692]356        {
[42162]357            if ( (call->data[i] == 0x00 && call->data[i+1] == 0x00 && call->data[i+2] == 0x00 && call->data[i+3] == 0x01 && (call->data[i+4] == 0x67 || call->data[i+4] == 0x68)) )
358            {
359                InsertPrivData = 0;
360                sps_pps_in_stream = 1;
361            }
362            i += 1;
363        }
364       
365        if (InsertPrivData && call->private_size > 0 /*&& initialHeader*/) // some rtsp streams can update codec data at runtime
366        {
[39692]367            initialHeader = 0;
368            iov[ic].iov_base  = call->private_data;
369            iov[ic++].iov_len = call->private_size;
370            PacketLength     += call->private_size;
371        }
372       
373        iov[ic].iov_base  = call->data;
374        iov[ic++].iov_len = call->len;
375        PacketLength     += call->len;
376       
377        iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, FakeStartCode);
378       
[42162]379        return call->WriteV(call->fd, iov, ic);
[39692]380    }
[40322]381    else if (!call->private_data || call->private_size < 7 || 1 != call->private_data[0])
[39692]382    {
[40322]383        h264_err("No valid private data available! [%d]\n", (int)call->private_size);
384        return 0;
[39692]385    }
386
[40322]387    uint32_t PacketLength = 0;
[39692]388   
389    ic = 0;
390    iov[ic++].iov_base = PesHeader;
391   
[42162]392    if (!avc3)
[39692]393    {
394        if (CodecData)
395        {
396            free(CodecData);
397            CodecData = NULL;
398        }
399       
[40322]400        uint8_t  *private_data = call->private_data;
401        uint32_t  private_size = call->private_size;
402   
403        if ( PreparCodecData(private_data, private_size, &NalLengthBytes))
404        {
405            UpdateExtraData(&private_data, &private_size, call->data, call->len);
406            PreparCodecData(private_data, private_size, &NalLengthBytes);
407        }
[39692]408       
[40322]409        if (private_data != call->private_data)
410        {
411            avc3 = 1;
412            free(private_data);
413            private_data = NULL;
414        }
415       
[39692]416        if (CodecData != NULL)
417        {
418            iov[ic].iov_base  = CodecData;
419            iov[ic++].iov_len = CodecDataLen;
420            PacketLength     += CodecDataLen;
[40322]421            initialHeader = 0;
[39692]422        }
423    }
424
425    if (CodecData != NULL)
426    {
[40322]427        uint32_t pos = 0;
[39692]428        do
429        {
430            if (ic >= IOVEC_SIZE)
431            {
432                h264_err(">> Drop data due to ic overflow\n");
433                break;
434            }
435           
[40322]436            uint32_t pack_len = 0;
437            uint32_t i = 0;
[39692]438            for (i = 0; i < NalLengthBytes; i++, pos++)
439            {
440                pack_len <<= 8;
441                pack_len += call->data[pos];
442            }
443           
444            if ( (pos + pack_len) > call->len )
445            {
446                pack_len = call->len - pos;
447            }
448           
449            iov[ic].iov_base  = Head;
450            iov[ic++].iov_len = sizeof(Head);
451            PacketLength += sizeof(Head);
452           
453            iov[ic].iov_base  = call->data + pos;
454            iov[ic++].iov_len = pack_len;
455            PacketLength     += pack_len;
456   
457            pos += pack_len;
458           
459        } while ((pos + NalLengthBytes) < call->len);
460       
461        h264_printf (10, "<<<< PacketLength [%d]\n", PacketLength);
462        iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, 0);
463       
[42162]464        len = call->WriteV(call->fd, iov, ic);
[39692]465        PacketLength += iov[0].iov_len;
466        if (PacketLength != len)
467        {
468            h264_err("<<<< not all data have been written [%d/%d]\n", len, PacketLength);
469        }
470    }
471
472    h264_printf (10, "< len %d\n", len);
473    return len;
474}
475
476static int writeReverseData(void* _call)
477{
478    WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
479   
480    return 0;
481}
482/* ***************************** */
483/* Writer  Definition            */
484/* ***************************** */
485
486static WriterCaps_t caps = {
487    "h264",
488    eVideo,
489    "V_MPEG4/ISO/AVC",
490    VIDEO_ENCODING_H264,
491    STREAMTYPE_MPEG4_H264,
492    CT_H264
493};
494
495struct Writer_s WriterVideoH264 = {
496    &reset,
497    &writeData,
498    &writeReverseData,
499    &caps
500};
Note: See TracBrowser for help on using the repository browser.