Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / IETF RTP/RTSP/SDP sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/ietf_dev.h>
27 :
28 : #ifndef GPAC_DISABLE_STREAMING
29 :
30 : #include <gpac/constants.h>
31 : #include <gpac/avparse.h>
32 :
33 7743 : static void mpa12_do_flush(GP_RTPPacketizer *builder, Bool start_new)
34 : {
35 : u8 *tmp;
36 : u32 tmp_size;
37 : /*flush*/
38 7743 : if (builder->pck_hdr) {
39 3867 : gf_bs_get_content(builder->pck_hdr, &tmp, &tmp_size);
40 3867 : builder->OnData(builder->cbk_obj, tmp, tmp_size, GF_TRUE);
41 3867 : gf_free(tmp);
42 :
43 3867 : if (gf_bs_get_size(builder->payload)) {
44 3867 : gf_bs_get_content(builder->payload, &tmp, &tmp_size);
45 3867 : builder->OnData(builder->cbk_obj, tmp, tmp_size, GF_FALSE);
46 3867 : gf_free(tmp);
47 : }
48 :
49 3867 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
50 3867 : gf_bs_del(builder->pck_hdr);
51 3867 : gf_bs_del(builder->payload);
52 3867 : builder->pck_hdr = NULL;
53 3867 : builder->payload = NULL;
54 3867 : builder->bytesInPacket = 0;
55 : }
56 11619 : if (!start_new) return;
57 :
58 3867 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
59 3867 : builder->pck_hdr = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
60 3867 : builder->payload = gf_bs_new(NULL, 0, GF_BITSTREAM_WRITE);
61 : /*create new RTP Packet */
62 3867 : builder->rtp_header.SequenceNumber += 1;
63 3867 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
64 3867 : builder->first_sl_in_rtp = GF_TRUE;
65 3867 : builder->bytesInPacket = 0;
66 : }
67 :
68 3876 : GF_Err gp_rtp_builder_do_mpeg12_audio(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
69 : {
70 : u32 pck_size;
71 : u16 offset;
72 :
73 : /*if no data flush, if nothing start if not enough space restart*/
74 3876 : if (!data || !builder->bytesInPacket || (builder->bytesInPacket + data_size > builder->Path_MTU)) {
75 3876 : mpa12_do_flush(builder, data ? GF_TRUE : GF_FALSE);
76 3876 : if (!data) return GF_OK;
77 : }
78 :
79 : offset = 0;
80 7734 : while (data_size) {
81 3867 : if (data_size + 4 < builder->Path_MTU) {
82 : pck_size = data_size;
83 : } else {
84 0 : pck_size = builder->Path_MTU - 4;
85 : }
86 3867 : if (builder->first_sl_in_rtp) {
87 3867 : gf_bs_write_u16(builder->pck_hdr, 0);
88 3867 : gf_bs_write_u16(builder->pck_hdr, offset);
89 3867 : builder->first_sl_in_rtp = GF_FALSE;
90 3867 : builder->bytesInPacket = 2;
91 : }
92 : /*add reference*/
93 3867 : if (builder->OnDataReference)
94 3828 : builder->OnDataReference(builder->cbk_obj, pck_size, offset);
95 : else
96 39 : gf_bs_write_data(builder->payload, data + offset, pck_size);
97 :
98 3867 : data_size -= pck_size;
99 3867 : builder->bytesInPacket += pck_size;
100 : /*start new packet if fragmenting*/
101 3867 : if (data_size) {
102 0 : offset += (u16) pck_size;
103 0 : mpa12_do_flush(builder, GF_TRUE);
104 : }
105 : }
106 : /*if offset or no aggregation*/
107 3867 : if (offset || !(builder->flags & GP_RTP_PCK_USE_MULTI) ) mpa12_do_flush(builder, GF_FALSE);
108 :
109 : return GF_OK;
110 : }
111 :
112 : #ifndef GPAC_DISABLE_AV_PARSERS
113 :
114 : #define MPEG12_PICTURE_START_CODE 0x00000100
115 : #define MPEG12_SEQUENCE_START_CODE 0x000001b3
116 :
117 2065 : GF_Err gp_rtp_builder_do_mpeg12_video(GP_RTPPacketizer *builder, u8 *data, u32 data_size, u8 IsAUEnd, u32 FullAUSize)
118 : {
119 : u32 startcode, pic_type, max_pck_size, offset, prev_slice, next_slice;
120 : Bool start_with_slice, slices_done, got_slice, first_slice, have_seq;
121 : u8 mpv_hdr[4];
122 : u8 *payload, *buffer;
123 :
124 : /*no flsuh (no aggregation)*/
125 2065 : if (!data) return GF_OK;
126 :
127 2061 : offset = 0;
128 : have_seq = GF_FALSE;
129 :
130 : while (1) {
131 : u32 oldoffset;
132 2208 : oldoffset = offset;
133 2208 : if (gf_mv12_next_start_code((unsigned char *) data + offset, data_size - offset, &offset, &startcode) < 0)
134 : break;
135 :
136 2208 : offset += oldoffset;
137 2208 : if (startcode == MPEG12_SEQUENCE_START_CODE) have_seq = GF_TRUE;
138 2208 : offset += 4;
139 :
140 2208 : if (startcode == MPEG12_PICTURE_START_CODE) break;
141 : }
142 :
143 2061 : max_pck_size = builder->Path_MTU - 4;
144 :
145 2061 : payload = data + offset;
146 2061 : pic_type = (payload[1] >> 3) & 0x7;
147 : /*first 6 bits (MBZ and T bit) not used*/
148 : /*temp ref on 10 bits*/
149 2061 : mpv_hdr[0] = (payload[0] >> 6) & 0x3;
150 2061 : mpv_hdr[1] = (payload[0] << 2) | ((payload[1] >> 6) & 0x3);
151 2061 : mpv_hdr[2] = pic_type;
152 2061 : mpv_hdr[3] = 0;
153 :
154 2061 : if ((pic_type==2) || (pic_type== 3)) {
155 : mpv_hdr[3] = (u8) ((((u32)payload[3]) << 5) & 0xf);
156 1920 : if ((payload[4] & 0x80) != 0) mpv_hdr[3] |= 0x10;
157 1920 : if (pic_type == 3) mpv_hdr[3] |= (payload[4] >> 3) & 0xf;
158 : }
159 :
160 : /*start packet*/
161 2061 : builder->rtp_header.TimeStamp = (u32) builder->sl_header.compositionTimeStamp;
162 2061 : builder->rtp_header.Marker = 1;
163 2061 : builder->rtp_header.SequenceNumber += 1;
164 2061 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
165 :
166 : buffer = data;
167 : prev_slice = 0;
168 2061 : start_with_slice = (gf_mv12_next_slice_start((unsigned char *)buffer, offset, data_size, &next_slice) >= 0) ? GF_TRUE : GF_FALSE;
169 2061 : offset = 0;
170 : slices_done = GF_FALSE;
171 : got_slice = start_with_slice;
172 : first_slice = GF_TRUE;
173 :
174 9001 : while (data_size > 0) {
175 : Bool last_pck;
176 : u32 len_to_write;
177 :
178 4879 : if (data_size <= max_pck_size) {
179 : len_to_write = data_size;
180 : last_pck = GF_TRUE;
181 : // prev_slice = 0;
182 : } else {
183 2818 : got_slice = (!first_slice && !slices_done && (next_slice <= max_pck_size)) ? GF_TRUE : GF_FALSE;
184 : first_slice = GF_FALSE;
185 : last_pck = GF_FALSE;
186 :
187 6549 : while (!slices_done && (next_slice <= max_pck_size)) {
188 : prev_slice = next_slice;
189 913 : if (gf_mv12_next_slice_start((unsigned char *)buffer, next_slice + 4, data_size, &next_slice) >= 0) {
190 : got_slice = GF_TRUE;
191 : } else {
192 : slices_done = GF_TRUE;
193 : }
194 : }
195 2818 : if (got_slice) len_to_write = prev_slice;
196 2818 : else len_to_write = MIN(max_pck_size, data_size);
197 : }
198 :
199 4879 : mpv_hdr[2] = pic_type;
200 :
201 4879 : if (have_seq) {
202 3 : mpv_hdr[2] |= 0x20;
203 : have_seq = GF_FALSE;
204 : }
205 4879 : if (first_slice) mpv_hdr[2] |= 0x10;
206 :
207 4879 : if (got_slice || last_pck) {
208 2061 : mpv_hdr[2] |= 0x08;
209 : // start_with_slice = GF_TRUE;
210 : } else {
211 : // start_with_slice = GF_FALSE;
212 : }
213 :
214 4879 : builder->OnData(builder->cbk_obj, mpv_hdr, 4, GF_FALSE);
215 4879 : if (builder->OnDataReference) {
216 4806 : builder->OnDataReference(builder->cbk_obj, len_to_write, offset);
217 : } else {
218 73 : builder->OnData(builder->cbk_obj, data + offset, len_to_write, GF_FALSE);
219 : }
220 :
221 4879 : builder->rtp_header.Marker = last_pck ? 1 : 0;
222 4879 : builder->OnPacketDone(builder->cbk_obj, &builder->rtp_header);
223 :
224 4879 : offset += len_to_write;
225 4879 : data_size -= len_to_write;
226 : prev_slice = 0;
227 4879 : next_slice -= len_to_write;
228 4879 : buffer += len_to_write;
229 :
230 4879 : if (!last_pck) {
231 2818 : builder->rtp_header.Marker = 0;
232 2818 : builder->rtp_header.SequenceNumber += 1;
233 2818 : builder->OnNewPacket(builder->cbk_obj, &builder->rtp_header);
234 : }
235 : }
236 : return GF_OK;
237 : }
238 :
239 : #endif
240 :
241 : #endif /*GPAC_DISABLE_STREAMING*/
|