Image and Font updates
[io/quag.git] / addons / AVCodec / source / IoAVCodec.c
blob26e9b55028b4b7b8c6ec7373a6576f3b329ddb4e
1 /*#io
2 AVCodec ioDoc(
3 docCopyright("Steve Dekorte", 2004)
4 docLicense("BSD revised")
5 docCategory("Media")
6 docDescription("""An object for encoding and decoding audio and video streams.""")
7 */
9 #include "IoAVCodec.h"
10 #include "List.h"
11 #include "IoState.h"
12 #include "IoNumber.h"
13 #include "IoSeq.h"
14 #include "IoList.h"
15 #include <limits.h>
16 //#include <math.h>
19 #define DATA(self) ((IoAVCodecData *)IoObject_dataPointer(self))
20 #define IVAR(name) (((IoAVCodecData *)IoObject_dataPointer(self))->name)
22 void IoAVCodec_registerIfNeeded(IoAVCodec *self)
24 avcodec_init();
25 avcodec_register_all();
26 av_register_all();
29 IoTag *IoAVCodec_newTag(void *state)
31 IoTag *tag = IoTag_newWithName_("AVCodec");
32 IoTag_state_(tag, state);
33 IoTag_cloneFunc_(tag, (IoTagCloneFunc *)IoAVCodec_rawClone);
34 IoTag_markFunc_(tag, (IoTagMarkFunc *)IoAVCodec_mark);
35 IoTag_freeFunc_(tag, (IoTagFreeFunc *)IoAVCodec_free);
36 return tag;
39 IoAVCodec *IoAVCodec_proto(void *state)
41 IoObject *self = IoObject_new(state);
42 IoObject_tag_(self, IoAVCodec_newTag(state));
44 IoObject_setDataPointer_(self, calloc(1, sizeof(IoAVCodecData)));
46 IVAR(inputBuffer) = IoSeq_new(state);
47 IVAR(outputBuffer) = IoSeq_new(state);
49 IoState_registerProtoWithFunc_(state, self, IoAVCodec_proto);
51 IoAVCodec_registerIfNeeded(self);
54 IoMethodTable methodTable[] = {
56 {"audioInputBuffer", IoAVCodec_audioInputBuffer},
57 {"audioOutputBuffer", IoAVCodec_audioOutputBuffer},
59 {"encodeCodecNames", IoAVCodec_encodeCodecNames},
60 {"decodeCodecNames", IoAVCodec_decodeCodecNames},
62 {"open", IoAVCodec_open},
63 {"close", IoAVCodec_close},
65 {"decode", IoAVCodec_decode},
66 {"isAtEnd", IoAVCodec_isAtEnd},
67 //{"encode", IoAVCodec_startEncoding},
69 {NULL, NULL},
71 IoObject_addMethodTable_(self, methodTable);
73 return self;
76 IoAVCodec *IoAVCodec_rawClone(IoAVCodec *proto)
78 IoObject *self = IoObject_rawClonePrimitive(proto);
79 IoObject_setDataPointer_(self, calloc(1, sizeof(IoAVCodecData)));
81 IVAR(inputBuffer) = IOCLONE(DATA(proto)->inputBuffer);
82 IVAR(outputBuffer) = IOCLONE(DATA(proto)->outputBuffer);
84 return self;
87 IoAVCodec *IoAVCodec_new(void *state)
89 IoObject *proto = IoState_protoWithInitFunction_(state, IoAVCodec_proto);
90 return IOCLONE(proto);
93 // -----------------------------------------------------------
95 void IoAVCodec_createContextIfNeeded(IoAVCodec *self)
97 if(!IVAR(packet))
99 IVAR(packet) = calloc(1, sizeof(AVPacket));
102 // video
104 // frames
105 if (!IVAR(frames))
107 IVAR(frames) = IoList_new(IOSTATE);
108 IoObject_setSlot_to_(self, IOSYMBOL("frames"), IVAR(frames));
111 // videoSize
113 UArray *sizeUArray = UArray_newWithData_type_encoding_size_copy_("", CTYPE_float32_t, CENCODING_NUMBER, 2, 1);
114 IoSeq *sizeSeq = IoSeq_newWithUArray_copy_(IOSTATE, sizeUArray, 0);
115 IoObject_setSlot_to_(self, IOSYMBOL("videoSize"), sizeSeq);
118 if (!IVAR(decodedFrame))
120 IVAR(decodedFrame) = avcodec_alloc_frame();
123 // audio
125 if(!IVAR(audioOutBuffer))
127 IVAR(audioOutBuffer) = malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
131 AVPicture *IoAVCode_allocDstPictureIfNeeded(IoAVCodec *self, int pix_fmt, int width, int height)
133 if(!IVAR(rgbPicture))
135 IVAR(rgbPicture) = calloc(1, sizeof(AVPicture));
136 avpicture_alloc(IVAR(rgbPicture), PIX_FMT_RGB24, width, height);
139 return IVAR(rgbPicture);
143 void IoAVCodec_freeContextIfNeeded(IoAVCodec *self)
145 //printf("IoAVCodec_freeContextIfNeeded\n");
147 IVAR(audioContext) = NULL;
148 IVAR(videoContext) = NULL;
150 if (IVAR(audioContext))
152 //avcodec_close(IVAR(audioContext));
153 //av_free(IVAR(audioContext));
154 IVAR(audioContext) = NULL;
157 if (IVAR(videoContext))
159 //avcodec_close(IVAR(audioContext));
160 //av_free(IVAR(audioContext));
161 IVAR(audioContext) = NULL;
164 if (IVAR(formatContext))
166 av_close_input_file(IVAR(formatContext));
167 //av_free(IVAR(formatContext));
168 IVAR(formatContext) = NULL;
171 if(IVAR(packet))
173 //free(IVAR(packet));
174 IVAR(packet) = NULL;
177 if (IVAR(audioOutBuffer))
179 //free(IVAR(audioOutBuffer));
180 IVAR(audioOutBuffer) = NULL;
183 if(IVAR(decodedFrame))
185 //av_free(IVAR(decodedFrame));
186 IVAR(decodedFrame) = NULL;
189 if(IVAR(rgbPicture))
191 avpicture_free(IVAR(rgbPicture));
192 //free(IVAR(rgbPicture));
193 IVAR(rgbPicture) = NULL;
196 //printf("IoAVCodec_freeContextIfNeeded done\n");
199 void IoAVCodec_free(IoAVCodec *self)
201 IoAVCodec_freeContextIfNeeded(self);
202 free(IoObject_dataPointer(self));
205 void IoAVCodec_mark(IoAVCodec *self)
207 if(IVAR(frames)) IoObject_shouldMark(IVAR(frames));
209 IoObject_shouldMark(IVAR(inputBuffer));
210 IoObject_shouldMark(IVAR(outputBuffer));
213 // -----------------------------------------------------------
215 void IoAVCodec_error_(IoAVCodec *self, IoMessage *m, char *s)
217 fprintf(stderr, s);
218 IoState_error_(IOSTATE, m, s);
221 IoObject *IoAVCodec_audioInputBuffer(IoAVCodec *self, IoObject *locals, IoMessage *m)
223 /*#io
224 docSlot("inputBuffer", "Returns the input buffer.")
226 return IVAR(inputBuffer);
229 IoObject *IoAVCodec_audioOutputBuffer(IoAVCodec *self, IoObject *locals, IoMessage *m)
231 /*#io
232 docSlot("outputBuffer", "Returns the output buffer.")
234 return IVAR(outputBuffer);
237 IoObject *IoAVCodec_decodeCodecNames(IoAVCodec *self, IoObject *locals, IoMessage *m)
239 /*#io
240 docSlot("decodeCodecNames", "Returns a list of strings with the names of the decode codecs.")
243 AVCodec *p = first_avcodec;
244 IoList *names = IoList_new(IOSTATE);
246 while (p)
248 if (p->decode)
250 IoList_rawAppend_(names, IOSYMBOL(p->name));
253 p = p->next;
256 return names;
259 IoObject *IoAVCodec_encodeCodecNames(IoAVCodec *self, IoObject *locals, IoMessage *m)
261 /*#io
262 docSlot("encodeCodecNames", "Returns a list of strings with the names of the encode codecs.")
265 AVCodec *p = first_avcodec;
266 IoList *names = IoList_new(IOSTATE);
268 while (p)
270 if (p->encode)
272 IoList_rawAppend_(names, IOSYMBOL(p->name));
275 p = p->next;
278 return names;
281 void IoAVCodec_ConvertShortToFloat(short *s, float *f, size_t sampleCount)
283 size_t i;
285 for (i = 0; i < sampleCount; i ++)
287 *f = (float)(*s) / (float)SHRT_MAX;
288 f ++;
289 *f = (float)(*s) / (float)SHRT_MAX;
290 s ++;
294 void IoAVCodec_ConvertFloatToShort(float *f, short *s, size_t sampleCount)
296 size_t i;
298 for (i = 0; i < sampleCount; i ++)
300 *s = (short)((*f) * SHRT_MAX);
301 s ++;
302 *s = (short)((*f) * SHRT_MAX);
303 f ++;
307 // -----------------------------------------------------------
309 #define INBUF_SIZE 4096
311 // ----------------------------------------------------------------------------------------------
313 IoObject *IoAVCodec_close(IoAVCodec *self, IoObject *locals, IoMessage *m)
315 IoAVCodec_registerIfNeeded(self);
316 IoAVCodec_freeContextIfNeeded(self);
317 return self;
320 int IoAVCodec_openFile(IoAVCodec *self)
322 AVInputFormat *inputFormat;
323 IoObject *fileName = IoObject_symbolGetSlot_(self, IOSYMBOL("path"));
324 int err = av_open_input_file(&IVAR(formatContext), CSTRING(fileName), NULL, 0, NULL);
325 return err;
328 IoObject *IoAVCodec_open(IoAVCodec *self, IoObject *locals, IoMessage *m)
330 int err;
332 IoAVCodec_registerIfNeeded(self);
333 IoAVCodec_freeContextIfNeeded(self);
334 IoAVCodec_createContextIfNeeded(self);
336 IVAR(isAtEnd) = 0;
338 err = IoAVCodec_openFile(self);
340 if (err != 0)
342 IoObject *fileName = IoObject_symbolGetSlot_(self, IOSYMBOL("path"));
343 IoState_error_(IOSTATE, m, "error %i opening file %s\n", err, CSTRING(fileName));
344 return IONIL(self);
347 IoAVCodec_findStreams(self);
348 av_read_play(IVAR(formatContext));
350 return self;
353 int IoAVCodec_findStreams(IoAVCodec *self)
355 AVFormatContext *formatContext = IVAR(formatContext);
356 int i;
358 av_find_stream_info(formatContext);
360 //printf("formatContext = %p streams = %i\n", (void *)formatContext, formatContext->nb_streams);
362 for(i = 0; i < formatContext->nb_streams; i++)
364 AVStream *stream = formatContext->streams[i];
365 AVCodecContext *codecContext = stream->codec;
367 switch(codecContext->codec_type)
369 case CODEC_TYPE_AUDIO:
370 IVAR(audioStreamIndex) = i;
372 AVCodec *codec = avcodec_find_decoder(codecContext->codec_id);
374 if (codec)
376 int err = avcodec_open(codecContext, codec);
378 if (err == 0)
380 IVAR(audioContext) = codecContext;
385 //printf("audioStreamIndex = %i\n", IVAR(audioStreamIndex));
386 IoObject_setSlot_to_(self, IOSYMBOL("audioChannels"), IONUMBER(codecContext->channels));
387 IoObject_setSlot_to_(self, IOSYMBOL("audioSampleRate"), IONUMBER(codecContext->sample_rate));
388 IoObject_setSlot_to_(self, IOSYMBOL("audioBitRate"), IONUMBER(codecContext->bit_rate));
389 IoObject_setSlot_to_(self, IOSYMBOL("audioDuration"), IONUMBER(stream->duration));
390 IoObject_setSlot_to_(self, IOSYMBOL("audioFrameCount"), IONUMBER(stream->nb_frames));
391 break;
393 case CODEC_TYPE_VIDEO:
395 IVAR(videoStreamIndex) = i;
398 AVCodec *codec = avcodec_find_decoder(codecContext->codec_id);
400 if (codec)
402 int err = avcodec_open(codecContext, codec);
404 if (err == 0)
406 IVAR(videoContext) = codecContext;
411 //printf("videoStreamIndex = %i\n", IVAR(videoStreamIndex));
413 float framePeriod = (((float)codecContext->time_base.num)/((float)codecContext->time_base.den));
414 UArray *sizeUArray = UArray_newWithData_type_encoding_size_copy_("", CTYPE_float32_t, CENCODING_NUMBER, 2, 1);
415 IoObject_setSlot_to_(self, IOSYMBOL("framePeriod"), IONUMBER(framePeriod));
416 IoObject_setSlot_to_(self, IOSYMBOL("videoDuration"), IONUMBER(stream->duration));
417 IoObject_setSlot_to_(self, IOSYMBOL("videoFrameCount"), IONUMBER(stream->nb_frames));
421 UArray *sizeUArray = UArray_newWithData_type_encoding_size_copy_("", CTYPE_float32_t, CENCODING_NUMBER, 2, 1);
422 IoSeq *sizeSeq = IoSeq_newWithUArray_copy_(IOSTATE, sizeUArray, 0);
423 UArray_at_putDouble_(sizeUArray, 0, codecContext->width);
424 UArray_at_putDouble_(sizeUArray, 1, codecContext->height);
425 IoObject_setSlot_to_(self, IOSYMBOL("videoSize"), sizeSeq);
428 break;
433 return 0;
436 IoObject *IoAVCodec_isAtEnd(IoAVCodec *self, IoObject *locals, IoMessage *m)
438 return IOBOOL(self, IVAR(isAtEnd));
441 IoObject *IoAVCodec_decode(IoAVCodec *self, IoObject *locals, IoMessage *m)
443 AVFormatContext *formatContext = IVAR(formatContext);
444 int audioStreamIndex = IVAR(audioStreamIndex);
445 int videoStreamIndex = IVAR(videoStreamIndex);
446 AVPacket *packet = IVAR(packet);
447 int ret;
450 if(IVAR(audioContext) == NULL && IVAR(videoContext) == NULL)
452 //printf("not open\n");
453 return IONIL(self);
456 ret = av_read_frame(formatContext, packet);
458 if (ret < 0)
460 //printf("av_read_frame ret = %i\n", ret);
462 if(ret == AVERROR_IO)
464 IVAR(isAtEnd) = 1;
467 return IONIL(self);
470 if (packet->stream_index == audioStreamIndex && IVAR(audioContext))
472 IoAVCodec_decodeAudioPacket(self,
473 formatContext->streams[audioStreamIndex]->codec,
474 packet->data, packet->size);
476 else if (packet->stream_index == videoStreamIndex && IVAR(videoContext))
478 IoAVCodec_decodeVideoPacket(self,
479 formatContext->streams[videoStreamIndex]->codec,
480 packet->data, packet->size);
482 else
484 av_free_packet(packet);
487 return self;
490 int IoAVCodec_decodeAudioPacket(IoAVCodec *self, AVCodecContext *c, uint8_t *inbuf, size_t size)
492 UArray *outba = IoSeq_rawUArray(IVAR(outputBuffer));
493 uint8_t *outbuf = IVAR(audioOutBuffer);
495 //UArray_setItemType_(outba, CTYPE_float32_t);
497 while (size > 0)
499 int outSize;
500 int len = avcodec_decode_audio(c, (int16_t *)outbuf, &outSize, inbuf, size);
502 if (len < 0)
504 printf("Error while decoding audio packet\n");
505 return -1;
508 if (outSize > 0)
510 // if a frame has been decoded, output it
511 // convert short ints to floats
513 size_t sampleCount = outSize / c->channels;
514 size_t oldSize = UArray_size(outba);
515 //UArray_setSize_(outba, oldSize + sampleCount); // knows it's a float32 array
516 UArray_setSize_(outba, oldSize + sampleCount * sizeof(float)); // knows it's a float32 array
518 IoAVCodec_ConvertShortToFloat((short *)outbuf, (float *)(UArray_bytes(outba) + oldSize), sampleCount);
521 size -= len;
522 inbuf += len;
525 return 0;
528 int IoAVCodec_decodeVideoPacket(IoAVCodec *self, AVCodecContext *c, uint8_t *inbuf, size_t size)
530 AVFrame *decodeFrame = IVAR(decodedFrame);
532 while (size > 0)
534 int got_picture;
535 size_t len = avcodec_decode_video(c, IVAR(decodedFrame), &got_picture, inbuf, size);
537 if (len < 0)
539 printf("Error while decoding video packet\n");
540 return -1;
543 if (got_picture)
545 IoList_rawAppend_(IVAR(frames), IoAVCode_frameSeqForAVFrame_(self, decodeFrame, c->pix_fmt, c->width, c->height));
548 size -= len;
549 inbuf += len;
552 return 0;
555 IoSeq *IoAVCode_frameSeqForAVFrame_(IoAVCodec *self, AVFrame *avframe, int srcPixelFormat, int width, int height)
557 AVPicture *rgbPicture = IoAVCode_allocDstPictureIfNeeded(self, srcPixelFormat, width, height);
558 AVPicture srcPicture;
559 int result;
561 memcpy(srcPicture.data, avframe->data, sizeof(uint8_t *) * 4);
562 memcpy(srcPicture.linesize, avframe->linesize, sizeof(int) * 4);
564 result = img_convert(rgbPicture, PIX_FMT_RGB24, &srcPicture, srcPixelFormat, width, height);
566 if (result)
568 printf("AVCodec: img_convert error?\n");
571 UArray *data = UArray_newWithData_type_encoding_size_copy_(rgbPicture->data[0], CTYPE_uint8_t, CENCODING_NUMBER, width * height * 3, 1);
573 return IoSeq_newWithUArray_copy_(IOSTATE, data, 0);