3 docCopyright("Steve Dekorte", 2004)
4 docLicense("BSD revised")
6 docDescription("""An object for encoding and decoding audio and video streams.""")
19 #define DATA(self) ((IoAVCodecData *)IoObject_dataPointer(self))
20 #define IVAR(name) (((IoAVCodecData *)IoObject_dataPointer(self))->name)
22 void IoAVCodec_registerIfNeeded(IoAVCodec
*self
)
25 avcodec_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
);
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},
71 IoObject_addMethodTable_(self
, methodTable
);
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
);
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
)
99 IVAR(packet
) = calloc(1, sizeof(AVPacket
));
107 IVAR(frames
) = IoList_new(IOSTATE
);
108 IoObject_setSlot_to_(self
, IOSYMBOL("frames"), IVAR(frames
));
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();
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
;
173 //free(IVAR(packet));
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
;
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
)
218 IoState_error_(IOSTATE
, m
, s
);
221 IoObject
*IoAVCodec_audioInputBuffer(IoAVCodec
*self
, IoObject
*locals
, IoMessage
*m
)
224 docSlot("inputBuffer", "Returns the input buffer.")
226 return IVAR(inputBuffer
);
229 IoObject
*IoAVCodec_audioOutputBuffer(IoAVCodec
*self
, IoObject
*locals
, IoMessage
*m
)
232 docSlot("outputBuffer", "Returns the output buffer.")
234 return IVAR(outputBuffer
);
237 IoObject
*IoAVCodec_decodeCodecNames(IoAVCodec
*self
, IoObject
*locals
, IoMessage
*m
)
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
);
250 IoList_rawAppend_(names
, IOSYMBOL(p
->name
));
259 IoObject
*IoAVCodec_encodeCodecNames(IoAVCodec
*self
, IoObject
*locals
, IoMessage
*m
)
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
);
272 IoList_rawAppend_(names
, IOSYMBOL(p
->name
));
281 void IoAVCodec_ConvertShortToFloat(short *s
, float *f
, size_t sampleCount
)
285 for (i
= 0; i
< sampleCount
; i
++)
287 *f
= (float)(*s
) / (float)SHRT_MAX
;
289 *f
= (float)(*s
) / (float)SHRT_MAX
;
294 void IoAVCodec_ConvertFloatToShort(float *f
, short *s
, size_t sampleCount
)
298 for (i
= 0; i
< sampleCount
; i
++)
300 *s
= (short)((*f
) * SHRT_MAX
);
302 *s
= (short)((*f
) * SHRT_MAX
);
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
);
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
);
328 IoObject
*IoAVCodec_open(IoAVCodec
*self
, IoObject
*locals
, IoMessage
*m
)
332 IoAVCodec_registerIfNeeded(self
);
333 IoAVCodec_freeContextIfNeeded(self
);
334 IoAVCodec_createContextIfNeeded(self
);
338 err
= IoAVCodec_openFile(self
);
342 IoObject
*fileName
= IoObject_symbolGetSlot_(self
, IOSYMBOL("path"));
343 IoState_error_(IOSTATE
, m
, "error %i opening file %s\n", err
, CSTRING(fileName
));
347 IoAVCodec_findStreams(self
);
348 av_read_play(IVAR(formatContext
));
353 int IoAVCodec_findStreams(IoAVCodec
*self
)
355 AVFormatContext
*formatContext
= IVAR(formatContext
);
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
);
376 int err
= avcodec_open(codecContext
, codec
);
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
));
393 case CODEC_TYPE_VIDEO
:
395 IVAR(videoStreamIndex
) = i
;
398 AVCodec
*codec
= avcodec_find_decoder(codecContext
->codec_id
);
402 int err
= avcodec_open(codecContext
, codec
);
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
);
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
);
450 if(IVAR(audioContext
) == NULL
&& IVAR(videoContext
) == NULL
)
452 //printf("not open\n");
456 ret
= av_read_frame(formatContext
, packet
);
460 //printf("av_read_frame ret = %i\n", ret);
462 if(ret
== AVERROR_IO
)
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
);
484 av_free_packet(packet
);
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);
500 int len
= avcodec_decode_audio(c
, (int16_t *)outbuf
, &outSize
, inbuf
, size
);
504 printf("Error while decoding audio packet\n");
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
);
528 int IoAVCodec_decodeVideoPacket(IoAVCodec
*self
, AVCodecContext
*c
, uint8_t *inbuf
, size_t size
)
530 AVFrame
*decodeFrame
= IVAR(decodedFrame
);
535 size_t len
= avcodec_decode_video(c
, IVAR(decodedFrame
), &got_picture
, inbuf
, size
);
539 printf("Error while decoding video packet\n");
545 IoList_rawAppend_(IVAR(frames
), IoAVCode_frameSeqForAVFrame_(self
, decodeFrame
, c
->pix_fmt
, c
->width
, c
->height
));
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
;
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
);
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);