video.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #define HL_NAME(n) video_##n
  2. #include <hl.h>
  3. #include <libavcodec/avcodec.h>
  4. #include <libavformat/avformat.h>
  5. #include <libswscale/swscale.h>
  6. typedef struct {
  7. void *finalizer;
  8. AVFormatContext *input;
  9. AVCodecContext *codec;
  10. AVFrame *frame;
  11. int videoStream;
  12. struct SwsContext *scale;
  13. } hl_video;
  14. static void hl_video_free( hl_video *v ) {
  15. avformat_close_input(&v->input);
  16. avcodec_free_context(&v->codec);
  17. av_frame_free(&v->frame);
  18. if( v->scale ) {
  19. sws_freeContext(v->scale);
  20. v->scale = NULL;
  21. }
  22. }
  23. HL_PRIM void HL_NAME(video_init)() {
  24. av_register_all();
  25. }
  26. static bool hl_video_init( hl_video *v, const char *file ) {
  27. AVCodec *codec;
  28. AVCodecContext *codecOrig;
  29. int i;
  30. if( avformat_open_input(&v->input, file, NULL, NULL) )
  31. return false;
  32. if( avformat_find_stream_info(v->input, NULL) < 0 )
  33. return false;
  34. v->videoStream = -1;
  35. for(i=0;i<(int)v->input->nb_streams; i++)
  36. if( v->input->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
  37. v->videoStream = i;
  38. break;
  39. }
  40. if( v->videoStream < 0 )
  41. return false;
  42. codecOrig = v->input->streams[v->videoStream]->codec;
  43. codec = avcodec_find_decoder(codecOrig->codec_id);
  44. if( codec == NULL )
  45. return false;
  46. v->codec = avcodec_alloc_context3(codec);
  47. avcodec_copy_context(v->codec, codecOrig);
  48. if( avcodec_open2(v->codec, codec,NULL) < 0 )
  49. return false;
  50. v->frame = av_frame_alloc();
  51. v->scale = sws_getContext(v->codec->width,v->codec->height, v->codec->pix_fmt, v->codec->width, v->codec->height, AV_PIX_FMT_RGBA, SWS_BILINEAR, NULL, NULL, NULL);
  52. return true;
  53. }
  54. HL_PRIM hl_video *HL_NAME(video_open)( const char *file ) {
  55. hl_video *v;
  56. v = hl_gc_alloc_finalizer(sizeof(hl_video));
  57. memset(v,0,sizeof(hl_video));
  58. v->finalizer = hl_video_free;
  59. if( !hl_video_init(v,file) ) {
  60. hl_video_free(v);
  61. return NULL;
  62. }
  63. return v;
  64. }
  65. HL_PRIM void HL_NAME(video_get_size)( hl_video *v, int *width, int *height ) {
  66. *width = v->codec->width;
  67. *height = v->codec->height;
  68. }
  69. HL_PRIM bool HL_NAME(video_decode_frame)( hl_video *v, vbyte *out, double *time ) {
  70. AVPacket packet;
  71. AVPicture i;
  72. int frameFinished = 0;
  73. while( !frameFinished ) {
  74. if( av_read_frame(v->input, &packet) < 0 )
  75. return false;
  76. if( packet.stream_index == v->videoStream && avcodec_decode_video2(v->codec, v->frame, &frameFinished, &packet) < 0 ) {
  77. av_free_packet(&packet);
  78. return false;
  79. }
  80. av_free_packet(&packet);
  81. }
  82. // extract to output
  83. if( out ) {
  84. i.data[0] = out;
  85. i.data[1] = out + 1;
  86. i.data[2] = out + 2;
  87. i.linesize[0] = v->codec->width * 4;
  88. i.linesize[1] = v->codec->width * 4;
  89. i.linesize[2] = v->codec->width * 4;
  90. sws_scale(v->scale, v->frame->data, v->frame->linesize, 0, v->codec->height, i.data, i.linesize);
  91. }
  92. if( time )
  93. *time = (double)av_frame_get_best_effort_timestamp(v->frame) * av_q2d(v->codec->pkt_timebase);
  94. return true;
  95. }
  96. HL_PRIM void HL_NAME(video_close)( hl_video *v ) {
  97. hl_video_free(v);
  98. }
  99. #define _VIDEO _ABSTRACT(hl_video)
  100. DEFINE_PRIM(_VOID, video_init, _NO_ARG);
  101. DEFINE_PRIM(_VIDEO, video_open, _BYTES);
  102. DEFINE_PRIM(_VOID, video_get_size, _VIDEO _REF(_I32) _REF(_I32));
  103. DEFINE_PRIM(_BOOL, video_decode_frame, _VIDEO _BYTES _REF(_F64));
  104. DEFINE_PRIM(_VOID, video_close, _VIDEO);