source: titan/libeplayer3/container/mpeg4p2_ffmpeg.c @ 40322

Last change on this file since 40322 was 40322, checked in by obi, 7 years ago

update libeplayer3 new version only buffer

File size: 7.5 KB
Line 
1//
2// mpeg4-part2 in mipsel receivers
3// http://forums.openpli.org/topic/39326-gstreamer10-and-mpeg4-part2/?hl=%2Bmpeg4+%2Bpart2
4//
5
6#define MPEG4P2_MAX_B_FRAMES_COUNT 5
7
8typedef struct
9{
10    int b_frames_count;
11    int first_ip_frame_written;
12    int64_t packet_duration;
13    AVPacket *b_frames[MPEG4P2_MAX_B_FRAMES_COUNT];
14    AVPacket *second_ip_frame;
15} Mpeg4P2Context;
16
17
18static void set_packet(AVPacket **pkt_dest, AVPacket *pkt_src)
19{
20    if (pkt_dest == NULL)
21        return;
22    if (*pkt_dest != NULL)
23    {
24        wrapped_packet_unref(*pkt_dest);
25        av_free(*pkt_dest);
26    }
27    *pkt_dest = av_malloc(sizeof(AVPacket));
28    av_copy_packet(*pkt_dest, pkt_src);
29}
30
31static int filter_packet(AVBitStreamFilterContext *bsf_ctx, AVCodecContext *enc_ctx, AVPacket *pkt)
32{
33    int ret;
34    AVPacket new_pkt = *pkt;
35    ret = av_bitstream_filter_filter(bsf_ctx, enc_ctx, NULL,
36            &new_pkt.data, &new_pkt.size,
37            pkt->data, pkt->size,
38            pkt->flags & AV_PKT_FLAG_KEY);
39    if (ret == 0 && new_pkt.data != pkt->data)
40    {
41        if ((ret = av_copy_packet(&new_pkt, pkt)) < 0)
42            return -1;
43        ret = 1;
44    }
45    if (ret > 0)
46    {
47        pkt->side_data = NULL;
48        pkt->side_data_elems = 0;
49        wrapped_packet_unref(pkt);
50        new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
51                av_buffer_default_free, NULL, 0);
52        if (!new_pkt.buf)
53            return -1;
54    }
55    if (ret < 0)
56    {
57        ffmpeg_err("Failed to filter bitstream with filter %s for stream %d with codec %s\n",
58                bsf_ctx->filter->name, pkt->stream_index,
59                avcodec_get_name(enc_ctx->codec_id));
60        return -1;
61    }
62    *pkt = new_pkt;
63    return 0;
64}
65
66static void mpeg4p2_context_reset(Mpeg4P2Context *context)
67{
68    if (context == NULL)
69        return;
70    int i;
71    for (i=0; i < MPEG4P2_MAX_B_FRAMES_COUNT; i++)
72    {
73        if (context->b_frames[i] != NULL)
74        {
75            wrapped_packet_unref(context->b_frames[i]);
76            av_free(context->b_frames[i]);
77        }
78        context->b_frames[i] = NULL;
79    }
80    if (context->second_ip_frame != NULL)
81    {
82        wrapped_packet_unref(context->second_ip_frame);
83        av_free(context->second_ip_frame);
84    }
85    context->second_ip_frame = NULL;
86
87    context->b_frames_count = 0;
88    context->first_ip_frame_written = 0;
89    context->packet_duration = 0;
90}
91
92static void mpeg4p2_write(Context_t *ctx, Track_t *track, int avContextIdx, int64_t *currentVideoPts, int64_t *latestPts, AVPacket *pkt)
93{
94    *currentVideoPts = track->pts = calcPts(avContextIdx, track->stream, pkt->pts);
95    if ((*currentVideoPts > *latestPts) && (*currentVideoPts != INVALID_PTS_VALUE))
96    {
97        *latestPts = *currentVideoPts;
98    }
99    track->dts = calcPts(avContextIdx, track->stream, pkt->dts);
100
101    AudioVideoOut_t avOut;
102    avOut.data       = pkt->data;
103    avOut.len        = pkt->size;
104    avOut.pts        = track->pts;
105    avOut.dts        = track->dts;
106    avOut.extradata  = track->extraData;
107    avOut.extralen   = track->extraSize;
108    avOut.frameRate  = track->frame_rate;
109    avOut.timeScale  = track->TimeScale;
110    avOut.width      = track->width;
111    avOut.height     = track->height;
112    avOut.type       = "video";
113
114    if (ctx->output->video->Write(ctx, &avOut) < 0)
115    {
116        ffmpeg_err("writing data to video device failed\n");
117    }
118}
119
120static int mpeg4p2_write_packet(Context_t *ctx, Mpeg4P2Context *mpeg4p2_ctx, Track_t *track, int cAVIdx, int64_t *pts_current, int64_t *pts_latest, AVPacket *pkt)
121{
122    uint8_t *data = pkt->data;
123    int data_len = pkt->size;
124    int pos = 0;
125    if (mpeg4p2_ctx->packet_duration == 0)
126    {
127        mpeg4p2_ctx->packet_duration = pkt->duration;
128    }
129    while (pos < data_len)
130    {
131        if (memcmp(&data[pos], "\x00\x00\x01\xb6", 4))
132        {
133            pos++;
134            continue;
135        }
136        pos += 4;
137        switch ((data[pos] & 0xC0) >> 6)
138        {
139            case 0: // I-Frame
140            case 1: // P-Frame
141                if (!mpeg4p2_ctx->first_ip_frame_written)
142                {
143                    mpeg4p2_ctx->first_ip_frame_written = 1;
144                    pkt->pts = pkt->dts + mpeg4p2_ctx->packet_duration;
145                    ffmpeg_printf(100, "Writing first I/P packet\n");
146                    mpeg4p2_write(ctx, track, cAVIdx, pts_current, pts_latest, pkt);
147                    return 0;
148                }
149                else if (!mpeg4p2_ctx->second_ip_frame)
150                {
151                    set_packet(&mpeg4p2_ctx->second_ip_frame, pkt);
152                    return 0;
153                }
154                else
155                {
156                    if (!mpeg4p2_ctx->b_frames_count)
157                    {
158                        mpeg4p2_ctx->second_ip_frame->pts = mpeg4p2_ctx->second_ip_frame->dts + mpeg4p2_ctx->packet_duration;
159                        ffmpeg_printf(100,"Writing second I/P packet(1)\n");
160                        mpeg4p2_write(ctx, track, cAVIdx, pts_current, pts_latest, mpeg4p2_ctx->second_ip_frame);
161                        set_packet(&mpeg4p2_ctx->second_ip_frame, pkt);
162                        return 0;
163                    }
164                    else
165                    {
166                        mpeg4p2_ctx->second_ip_frame->pts = mpeg4p2_ctx->b_frames[mpeg4p2_ctx->b_frames_count -1]->dts + mpeg4p2_ctx->packet_duration;
167                        mpeg4p2_ctx->b_frames[0]->pts = mpeg4p2_ctx->second_ip_frame->dts + mpeg4p2_ctx->packet_duration;
168                        int i;
169                        for (i =1; i < mpeg4p2_ctx->b_frames_count; i++)
170                        {
171                            mpeg4p2_ctx->b_frames[i]->pts = mpeg4p2_ctx->b_frames[i-1]->dts + mpeg4p2_ctx->packet_duration;
172                        }
173                        ffmpeg_printf(100, "Writing second I/P packet(2)\n");
174                        mpeg4p2_write(ctx, track, cAVIdx, pts_current, pts_latest, mpeg4p2_ctx->second_ip_frame);
175                        set_packet(&mpeg4p2_ctx->second_ip_frame, pkt);
176                        for (i =0; i< mpeg4p2_ctx->b_frames_count; i++)
177                        {
178                            ffmpeg_printf(100, "Writing B-frame[%d]\n", i);
179                            mpeg4p2_write(ctx, track, cAVIdx, pts_current, pts_latest, mpeg4p2_ctx->b_frames[i]);
180                        }
181                        mpeg4p2_ctx->b_frames_count = 0;
182                        return 0;
183                    }
184                }
185                break;
186            case 3: // S-Frame
187                break;
188            case 2: // B-Frame
189                if (!mpeg4p2_ctx->second_ip_frame)
190                {
191                    ffmpeg_err("Cannot predict B-Frame without surrounding I/P-Frames, dropping...");
192                    return 0;
193                }
194                if (mpeg4p2_ctx->b_frames_count == MPEG4P2_MAX_B_FRAMES_COUNT)
195                {
196                    ffmpeg_err("Oops max B-Frames count = %d, reached", MPEG4P2_MAX_B_FRAMES_COUNT);
197                    // not recoverable, to fix just increase MPEG4P2_MAX_B_FRAMES_COUNT
198                    return -1;
199                }
200                else
201                {
202                    ffmpeg_printf(100, "Storing B-Frame\n");
203                    set_packet(&mpeg4p2_ctx->b_frames[mpeg4p2_ctx->b_frames_count++], pkt);
204                    return 0;
205                }
206            case 4:
207            default:
208                break;
209        }
210    }
211    return 0;
212}
213
Note: See TracBrowser for help on using the repository browser.