1 /*
2 Ming, an SWF output library
3 Copyright (C) 2002 Opaque Industries - http://www.opaque.net/
4
5 2.2.2007 Klaus Rechert
6
7 This library 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 This library 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 this library; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
21 */
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "input.h"
26 #include "libming.h"
27 #include "error.h"
28 #include "flv.h"
29
readAudioHdr(FLVStream * flv,FLVTag * tag)30 static inline int readAudioHdr(FLVStream *flv, FLVTag *tag)
31 {
32 int ichar;
33 ichar = SWFInput_getChar(flv->input);
34 if(ichar == EOF)
35 return -1;
36 tag->hdr.audio.format = (0xf0 & ichar);
37 tag->hdr.audio.samplingRate = (0xc & ichar);
38 tag->hdr.audio.sampleSize = (0x2 & ichar);
39 tag->hdr.audio.channel = 0x1 & ichar;
40 return 0;
41 }
42
readVideoHdr(FLVStream * flv,FLVTag * tag)43 static inline int readVideoHdr(FLVStream *flv, FLVTag *tag)
44 {
45 int ichar;
46 ichar = SWFInput_getChar(flv->input);
47 if(ichar == EOF)
48 return -1;
49
50 tag->hdr.video.frameType = (0xf0 & ichar);
51 tag->hdr.video.codec = 0x0f & ichar;
52 return 0;
53 }
54
FLVStream_skipTagData(FLVStream * flv,FLVTag * tag)55 long FLVStream_skipTagData(FLVStream *flv, FLVTag *tag)
56 {
57 if(flv == NULL || tag == NULL)
58 return -1;
59
60 SWFInput_seek(flv->input, tag->data + tag->dataSize + 4, SEEK_SET);
61
62 return SWFInput_tell(flv->input);
63 }
64
destroyFLVStream(FLVStream * flv)65 void destroyFLVStream(FLVStream *flv)
66 {
67 free(flv);
68 }
69
FLVStream_fromInput(SWFInput input)70 FLVStream *FLVStream_fromInput(SWFInput input)
71 {
72 int ichar;
73 unsigned long ulchar;
74 FLVStream *flv;
75
76 if(!input)
77 return NULL;
78
79 ichar = SWFInput_getChar(input);
80 if(ichar == EOF || ichar != 'F')
81 return NULL;
82
83 ichar = SWFInput_getChar(input);
84 if(ichar == EOF || ichar != 'L')
85 return NULL;
86
87 ichar = SWFInput_getChar(input);
88 if(ichar == EOF || ichar != 'V')
89 return NULL;
90
91 flv = (FLVStream *)malloc(sizeof(FLVStream));
92 if(flv == NULL)
93 return NULL;
94 flv->input = input;
95
96 ichar = SWFInput_getChar(input);
97 if(ichar != EOF)
98 flv->version = ichar;
99
100 flv->has_video = 0;
101 flv->has_audio = 0;
102 ichar = SWFInput_getChar(input);
103 if(ichar != EOF)
104 {
105 if(ichar & FLV_AUDIO_PRESENT)
106 flv->has_audio = 1;
107
108 if(ichar & FLV_VIDEO_PRESENT)
109 flv->has_video = 1;
110 }
111
112 ulchar = SWFInput_getUInt32_BE(input);
113 flv->offset = ulchar + 4;
114 flv->stream_start = flv->offset;
115 return flv;
116 }
117
FLVStream_rewind(FLVStream * flv)118 void FLVStream_rewind(FLVStream *flv)
119 {
120 SWFInput_seek(flv->input, flv->offset, SEEK_SET);
121 }
122
FLVStream_nextTag(FLVStream * flv,FLVTag * tag,FLVTag * prev)123 int FLVStream_nextTag(FLVStream *flv, FLVTag *tag, FLVTag *prev)
124 {
125 int ichar;
126 unsigned long ulchar;
127
128 if(prev == NULL)
129 SWFInput_seek(flv->input, flv->offset, SEEK_SET);
130 else
131 {
132 unsigned long off;
133 if(prev->data < 0)
134 return -1;
135
136 off = prev->data + prev->dataSize + 4;
137 SWFInput_seek(flv->input, off, SEEK_SET);
138 }
139
140 tag->offset = SWFInput_tell(flv->input);
141
142 tag->stream = flv;
143
144 ichar = SWFInput_getChar(flv->input);
145 if(ichar == EOF)
146 return -1;
147 if(ichar != FLV_VIDEOTAG && ichar != FLV_AUDIOTAG && ichar != FLV_SCRIPTTAG)
148 {
149 SWF_warn("FLV: stream out of sync!\n");
150 return -1;
151 }
152 tag->tagType = ichar;
153
154 ulchar = SWFInput_getUInt24_BE(flv->input);
155 tag->dataSize = ulchar;
156
157 ulchar = SWFInput_getUInt24_BE(flv->input);
158 tag->timeStamp = ulchar;
159
160 ulchar = SWFInput_getUInt32_BE(flv->input);
161 if(ulchar)
162 {
163 SWF_warn("FLV: stream out of sync!\n");
164 return -1;
165 }
166
167 tag->data = SWFInput_tell(flv->input);
168 if(tag->tagType == FLV_VIDEOTAG)
169 readVideoHdr(flv, tag);
170 else if(tag->tagType == FLV_AUDIOTAG)
171 readAudioHdr(flv, tag);
172
173 return 0;
174 }
175
FLVStream_nextTagType(FLVStream * flv,FLVTag * tag,FLVTag * prev,int type)176 int FLVStream_nextTagType(FLVStream *flv, FLVTag *tag, FLVTag *prev, int type)
177 {
178
179 while(FLVStream_nextTag(flv, tag, prev) == 0)
180 {
181 if(tag->tagType == type)
182 return 0;
183 prev = tag;
184 }
185 return -1;
186
187 }
188
FLVStream_getDuration(FLVStream * flv,int type)189 unsigned int FLVStream_getDuration(FLVStream *flv, int type)
190 {
191 unsigned int duration = 0;
192 FLVTag tag, *p_tag = NULL;
193
194 while(FLVStream_nextTag(flv, &tag, p_tag) == 0)
195 {
196 if(tag.tagType == type)
197 {
198 /* optimistic approach */
199 duration = tag.timeStamp;
200 }
201 p_tag = &tag;
202 }
203 return duration;
204 }
205
FLVStream_getNumFrames(FLVStream * flv,int type)206 int FLVStream_getNumFrames(FLVStream *flv, int type)
207 {
208 int numFrames = 0;
209 FLVTag tag, *p_tag = NULL;
210
211 while(FLVStream_nextTag(flv, &tag, p_tag) == 0)
212 {
213 if(tag.tagType == type)
214 numFrames++;
215 p_tag = &tag;
216 }
217 return numFrames;
218 }
219
FLVTag_getPayloadInput(FLVTag * tag)220 SWFInput FLVTag_getPayloadInput(FLVTag *tag)
221 {
222 int length;
223 SWFInput input;
224 if(tag == NULL || tag->stream == NULL)
225 return NULL;
226
227 input = tag->stream->input;
228
229 /* screen video needs this extra byte undocumented! */
230 if(tag->tagType == FLV_VIDEOTAG
231 && tag->hdr.video.codec == VIDEO_CODEC_SCREEN)
232 {
233 length = tag->dataSize;
234 SWFInput_seek(input, tag->data, SEEK_SET);
235 }
236 else if(tag->tagType == FLV_VIDEOTAG
237 && tag->hdr.video.codec == VIDEO_CODEC_VP6)
238 {
239 length = tag->dataSize - 2;
240 SWFInput_seek(input, tag->data + 2, SEEK_SET);
241 }
242 else /* skip flv-audio/video-data byte */
243 {
244 length = tag->dataSize - 1;
245 SWFInput_seek(input, tag->data + 1, SEEK_SET);
246 }
247
248 return newSWFInput_input(input, length);
249 }
250
FLVStream_setStreamOffset(FLVStream * flv,unsigned int msecs)251 int FLVStream_setStreamOffset(FLVStream *flv, unsigned int msecs)
252 {
253 FLVTag tag, *p_tag = NULL;
254
255 /* reset stream offset */
256 flv->offset = flv->stream_start;
257
258 while(FLVStream_nextTag(flv, &tag, p_tag) == 0)
259 {
260 if(tag.timeStamp >= msecs)
261 {
262 flv->offset = tag.offset;
263 return 0;
264 }
265 p_tag = &tag;
266 }
267 return -1;
268 }
269
270