diff --git a/include/notcurses.h b/include/notcurses.h index 9f7e05ed1..89a6742fa 100644 --- a/include/notcurses.h +++ b/include/notcurses.h @@ -18,6 +18,7 @@ API const char* notcurses_version(void); struct cell; // a coordinate on an ncplane: an EGC plus styling struct ncplane; // a drawable notcurses surface, composed of cells +struct ncvisual; // a visual bit of multimedia opened with LibAV struct notcurses; // notcurses state for a given terminal, composed of ncplanes // A cell corresponds to a single character cell on some plane, which can be @@ -427,7 +428,9 @@ ncplane_rounded_box_cells(struct ncplane* n, cell* ul, cell* ur, cell* ll, } // multimedia functionality -API int notcurses_visual_open(struct notcurses* nc, const char* filename); +API struct ncvisual* notcurses_visual_open(struct notcurses* nc, + const char* filename); +API void ncvisual_destroy(struct ncvisual* ncv); #undef API diff --git a/src/lib/libav.c b/src/lib/libav.c index ffe08953f..b6021e850 100644 --- a/src/lib/libav.c +++ b/src/lib/libav.c @@ -2,86 +2,89 @@ #include #include "notcurses.h" -int notcurses_visual_open(struct notcurses* nc __attribute__ ((unused)), - const char* filename){ - AVFormatContext* ps = NULL; - int ret = avformat_open_input(&ps, filename, NULL, NULL); +typedef struct ncvisual { + AVFormatContext* fmtctx; + AVCodecContext* codecctx; + AVFrame* frame; + AVCodec* codec; + AVPacket* packet; +} ncvisual; + +static ncvisual* +ncvisual_create(void){ + ncvisual* ret = malloc(sizeof(*ret)); + if(ret == NULL){ + return NULL; + } + memset(ret, 0, sizeof(*ret)); + return ret; +} + +void ncvisual_destroy(ncvisual* ncv){ + if(ncv){ + avcodec_close(ncv->codecctx); + avcodec_free_context(&ncv->codecctx); + av_frame_free(&ncv->frame); + av_packet_free(&ncv->packet); + avformat_close_input(&ncv->fmtctx); + free(ncv); + } +} + +ncvisual* notcurses_visual_open(struct notcurses* nc __attribute__ ((unused)), + const char* filename){ + ncvisual* ncv = ncvisual_create(); + if(ncv == NULL){ + return NULL; + } + int ret = avformat_open_input(&ncv->fmtctx, filename, NULL, NULL); if(ret < 0){ fprintf(stderr, "Couldn't open %s (%s)\n", filename, av_err2str(ret)); - return ret; + goto err; } - if((ret = avformat_find_stream_info(ps, NULL)) < 0){ + if((ret = avformat_find_stream_info(ncv->fmtctx, NULL)) < 0){ fprintf(stderr, "Error extracting stream info from %s (%s)\n", filename, av_err2str(ret)); - avformat_close_input(&ps); - return ret; + goto err; } -av_dump_format(ps, 0, filename, false); - AVPacket* packet = av_packet_alloc(); - if((ret = av_read_frame(ps, packet)) < 0){ +av_dump_format(ncv->fmtctx, 0, filename, false); + if((ncv->packet = av_packet_alloc()) == NULL){ + fprintf(stderr, "Couldn't allocate packet for %s\n", filename); + goto err; + } + if((ret = av_read_frame(ncv->fmtctx, ncv->packet)) < 0){ fprintf(stderr, "Error reading frame info from %s (%s)\n", filename, av_err2str(ret)); - av_packet_free(&packet); - avformat_close_input(&ps); - return -1; + goto err; } - AVCodec* codec; - if((ret = av_find_best_stream(ps, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0)) < 0){ + if((ret = av_find_best_stream(ncv->fmtctx, AVMEDIA_TYPE_VIDEO, -1, -1, &ncv->codec, 0)) < 0){ fprintf(stderr, "Couldn't find visuals in %s (%s)\n", filename, av_err2str(ret)); - av_packet_free(&packet); - avformat_close_input(&ps); - return -1; + goto err; } - if(codec == NULL){ + if(ncv->codec == NULL){ fprintf(stderr, "Couldn't find decoder for %s\n", filename); - av_packet_free(&packet); - avformat_close_input(&ps); - return -1; + goto err; } - /* - stream = ret; - AVStream* avstream = ps->streams[stream]; - AVCodecContext* codecctx = avstream->codec; - AVCodec* codec = avcodec_find_decoder(codecctx->codec_id); - if(codec == NULL){ - fprintf(stderr, "Couldn't find decoder for %s (%s)\n", filename); - avcodec_close(codecctx); - av_packet_free(&packet); - avformat_close_input(&ps); - return -1; + if((ncv->codecctx = avcodec_alloc_context3(ncv->codec)) == NULL){ + fprintf(stderr, "Couldn't allocate decoder for %s\n", filename); + goto err; } - */ - AVCodecContext* codecctx = avcodec_alloc_context3(codec); - if((ret = avcodec_open2(codecctx, codec, NULL)) < 0){ + if((ret = avcodec_open2(ncv->codecctx, ncv->codec, NULL)) < 0){ fprintf(stderr, "Couldn't open codec for %s (%s)\n", filename, av_err2str(ret)); - avcodec_free_context(&codecctx); - av_packet_free(&packet); - avformat_close_input(&ps); - return -1; + goto err; } - if((ret = avcodec_send_packet(codecctx, packet)) < 0){ + if((ret = avcodec_send_packet(ncv->codecctx, ncv->packet)) < 0){ fprintf(stderr, "Error decoding packet from %s (%s)\n", filename, av_err2str(ret)); - avcodec_close(codecctx); - avcodec_free_context(&codecctx); - av_packet_free(&packet); - avformat_close_input(&ps); - return -1; + goto err; } - AVFrame* frame = av_frame_alloc(); - if(frame == NULL){ - avcodec_close(codecctx); - avcodec_free_context(&codecctx); - av_packet_free(&packet); - avformat_close_input(&ps); - return -1; + if((ncv->frame = av_frame_alloc()) == NULL){ + fprintf(stderr, "Couldn't allocate frame for %s\n", filename); + goto err; } + return ncv; - // FIXME - avcodec_close(codecctx); - avcodec_free_context(&codecctx); - av_frame_free(&frame); - av_packet_free(&packet); - avformat_close_input(&ps); - return 0; +err: + ncvisual_destroy(ncv); + return NULL; }