diff options
| author | Tim Redfern <tim@eclectronics.org> | 2013-09-11 16:11:47 +0100 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2013-09-11 16:11:47 +0100 |
| commit | f9694b7d4f1648a0fa984e7cc428bbc9eea86ca0 (patch) | |
| tree | 59e14e57c52e82927963ef71bf83de0f665c42cb /rotord/src | |
| parent | 1f52520db005e056e131f511418e4b71bc9e89fd (diff) | |
ffms2 library for video loader
Diffstat (limited to 'rotord/src')
| -rw-r--r-- | rotord/src/ffmpeg-fas_wrapper.cpp | 1 | ||||
| -rw-r--r-- | rotord/src/ffmpeg-fas_wrapper.h | 16 | ||||
| -rw-r--r-- | rotord/src/ffmpeg_fas.c | 948 | ||||
| -rw-r--r-- | rotord/src/ffmpeg_fas.h | 130 | ||||
| -rw-r--r-- | rotord/src/graph.cpp | 2 | ||||
| -rw-r--r-- | rotord/src/graph.h | 1 | ||||
| -rw-r--r-- | rotord/src/libavwrapper.cpp | 60 | ||||
| -rw-r--r-- | rotord/src/libavwrapper.h | 64 | ||||
| -rw-r--r-- | rotord/src/ofUtils.o | bin | 0 -> 593072 bytes | |||
| -rw-r--r-- | rotord/src/private_errors.h | 32 | ||||
| -rw-r--r-- | rotord/src/rendercontext.h | 1 | ||||
| -rw-r--r-- | rotord/src/rotor.cpp | 4 | ||||
| -rw-r--r-- | rotord/src/rotor.h | 71 | ||||
| -rw-r--r-- | rotord/src/seek_indices.c | 319 | ||||
| -rw-r--r-- | rotord/src/seek_indices.h | 94 |
15 files changed, 190 insertions, 1553 deletions
diff --git a/rotord/src/ffmpeg-fas_wrapper.cpp b/rotord/src/ffmpeg-fas_wrapper.cpp deleted file mode 100644 index f1b81c2..0000000 --- a/rotord/src/ffmpeg-fas_wrapper.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "ffmpeg-fas_wrapper.h" diff --git a/rotord/src/ffmpeg-fas_wrapper.h b/rotord/src/ffmpeg-fas_wrapper.h deleted file mode 100644 index dedff62..0000000 --- a/rotord/src/ffmpeg-fas_wrapper.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ffmpeg_fas_wrapper_H -#define ffmpeg_fas_wrapper_H - -#include <string> -#include "ffmpeg_fas.h" - - -namespace ffmpeg_fas { - class decoder - { - public: - bool open(std::string& fileName); - fas_raw_image_type frame; - }; -} -#endif diff --git a/rotord/src/ffmpeg_fas.c b/rotord/src/ffmpeg_fas.c deleted file mode 100644 index 19e9655..0000000 --- a/rotord/src/ffmpeg_fas.c +++ /dev/null @@ -1,948 +0,0 @@ -/***************************************************************************** - * Copyright 2008. Pittsburgh Pattern Recognition, Inc. - * - * This file is part of the Frame Accurate Seeking extension library to - * ffmpeg (ffmpeg-fas). - * - * ffmpeg-fas is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * The ffmpeg-fas library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -#include "ffmpeg_fas.h" - -#if defined( _WIN32 ) && defined( STATIC_DLL ) -extern "C" -{ - #include "libavformat/avformat.h" - #include "libavcodec/avcodec.h" - //int img_convert(AVPicture *dst, int dst_pix_fmt, const AVPicture *src, int src_pix_fmt, int src_width, int src_height); -} -#else -#include "libavformat/avformat.h" -#include "libavcodec/avcodec.h" -#endif /* _WIN32 && STATIC_DLL */ - -#include "seek_indices.h" -#include "private_errors.h" - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> - -#define FIRST_FRAME_INDEX 0 -#define NUM_POSSIBLE_ERRORS 9 - -enum PixelFormat fmt; - -/**** Private Types ***********************************************************/ - -typedef struct fas_context_struct { - fas_boolean_type is_video_active; - fas_boolean_type is_frame_available; - - int current_frame_index; - - seek_table_type seek_table; - - /* ffmpeg */ - AVFormatContext *format_context; - AVCodecContext *codec_context; - int stream_idx; - - AVFrame *frame_buffer; // internal buffer - - AVFrame *rgb_frame_buffer; // extra AVFrames (for color conversion) - uint8_t *rgb_buffer; // actual data buffer for rgb_frame_buffer (needs to be freed seperately) - fas_boolean_type rgb_already_converted; // color_convert(frame_buffer) == rgb_frame_buffer (so we don't need to repeat conversions) - - AVFrame *gray8_frame_buffer; - uint8_t *gray8_buffer; - fas_boolean_type gray8_already_converted; - - int64_t current_dts; // decoding timestamp of the most recently parsed packet - int64_t previous_dts; // for previous packet (always use previous packet for seek_table (workaround)) - int64_t keyframe_packet_dts; // dts of most recent keyframe packet - int64_t first_dts; // for very first packet (needed in seek, for first keyframe) - -} fas_context_type; - -static char* invalid_error_code = "not a valid error code"; -static char *gbl_error_strings[NUM_POSSIBLE_ERRORS] = -{ - "fas_success", - "fas_failure", - "fas_invalid_argument", - "fas_out_of_memory", - "fas_unsupported_format", - "fas_unsupported_codec", - "fas_no_more_frames", - "fas_decoding_error", - "fas_seek_error" -}; - -char* fas_error_message(fas_error_type error) -{ - if ((error < 0) || (error >= NUM_POSSIBLE_ERRORS)) - return invalid_error_code; - - return gbl_error_strings[error]; -} - -void private_show_warning (const char *message); -fas_error_type private_show_error (const char *message, fas_error_type error); -fas_error_type private_convert_to_rgb (fas_context_ref_type ctx); -fas_error_type private_seek_to_nearest_key (fas_context_ref_type context, int target_index, int offset); -fas_error_type private_complete_seek_table (fas_context_ref_type context); - - -void fas_set_logging (fas_boolean_type logging) -{ - if (logging == FAS_TRUE) - { - SHOW_ERROR_MESSAGES = 1; - SHOW_WARNING_MESSAGES = 1; -#ifndef _WIN32 - av_log_set_level(AV_LOG_INFO); //TJR 080913 -#endif - } - else - { - SHOW_ERROR_MESSAGES = 0; - SHOW_WARNING_MESSAGES = 0; -#ifndef _WIN32 - av_log_set_level(AV_LOG_QUIET); //TJR 080913 -#endif - } -} - -/* Set the output image colorspace */ -void fas_set_format(fas_color_space_type format) -{ - switch (format) - { - case FAS_GRAY8: - fmt = PIX_FMT_GRAY8; - break; - case FAS_ARGB32: - fmt = PIX_FMT_RGB32_1; - break; - case FAS_ABGR32: - fmt = PIX_FMT_BGR32_1; - break; - case FAS_YUV420P: - fmt = PIX_FMT_YUV420P; - break; - case FAS_YUYV422: - fmt = PIX_FMT_YUYV422; - break; - case FAS_UYVY422: - fmt = PIX_FMT_UYVY422; - break; - case FAS_YUV422P: - fmt = PIX_FMT_YUV422P; - break; - case FAS_YUV444P: - fmt = PIX_FMT_YUV444P; - break; - case FAS_RGB24: - fmt = PIX_FMT_RGB24; - break; - case FAS_BGR24: - fmt = PIX_FMT_BGR24; - break; - default: - fmt = PIX_FMT_RGB24; - break; - } -} - - -void fas_initialize (fas_boolean_type logging, fas_color_space_type format) -{ - fas_set_logging(logging); - fas_set_format(format); - av_register_all(); - - return; -} - -/* fas_open_video */ - -fas_error_type fas_open_video (fas_context_ref_type *context_ptr, char *file_path) -{ - if (NULL == context_ptr) - return private_show_error ("NULL context pointer provided", FAS_INVALID_ARGUMENT); - - // seek_error_type seek_error; - fas_context_ref_type fas_context; - - *context_ptr = NULL; // set returned context to NULL in case of error - - fas_context = (fas_context_ref_type)malloc (sizeof (fas_context_type)); - memset(fas_context, 0, sizeof(fas_context_type)); - - if (NULL == fas_context) - return private_show_error ("unable to allocate buffer", FAS_OUT_OF_MEMORY); - - fas_context->is_video_active = FAS_TRUE; - fas_context->is_frame_available = FAS_TRUE; - fas_context->current_frame_index = FIRST_FRAME_INDEX - 1; - fas_context->current_dts = AV_NOPTS_VALUE; - fas_context->previous_dts = AV_NOPTS_VALUE; - fas_context->keyframe_packet_dts = AV_NOPTS_VALUE; - fas_context->first_dts = AV_NOPTS_VALUE; - - fas_context->seek_table = seek_init_table (-1); /* default starting size */ - - if (avformat_open_input( &(fas_context->format_context), file_path, NULL, NULL ) != 0) //TJR updated from av_open_file 080913 - { - fas_close_video(fas_context); - return private_show_error ("failure to open file", FAS_UNSUPPORTED_FORMAT); - } - - if (avformat_find_stream_info (fas_context->format_context,NULL) < 0) //TJR updated from av_find_stream_info 080913 - { - fas_close_video(fas_context); - return private_show_error ("could not extract stream information", FAS_UNSUPPORTED_FORMAT); - } - - if (SHOW_WARNING_MESSAGES) - av_dump_format(fas_context->format_context, 0, file_path, 0); - - int stream_idx; - for (stream_idx = 0; stream_idx < fas_context->format_context->nb_streams; stream_idx++) - { - if (fas_context->format_context->streams[stream_idx]->codec->codec_type == AVMEDIA_TYPE_VIDEO) - { - fas_context->stream_idx = stream_idx; - fas_context->codec_context = fas_context->format_context->streams[stream_idx]->codec; - break; - } - } - - if (fas_context->codec_context == 0) - { - fas_close_video(fas_context); - return private_show_error ("failure to find a video stream", FAS_UNSUPPORTED_FORMAT); - } - - AVCodec *codec = avcodec_find_decoder (fas_context->codec_context->codec_id); - - if (!codec) - { - fas_context->codec_context = 0; - fas_close_video(fas_context); - return private_show_error("failed to find correct video codec", FAS_UNSUPPORTED_CODEC); - } - - if (avcodec_open2(fas_context->codec_context, codec,NULL) < 0) //TJR 080913 added NULL options dictionary - { - fas_context->codec_context = 0; - fas_close_video(fas_context); - return private_show_error ("failed to open codec", FAS_UNSUPPORTED_CODEC); - } - - fas_context->frame_buffer = avcodec_alloc_frame (); - if (fas_context->frame_buffer == NULL) - { - fas_close_video(fas_context); - return private_show_error ("failed to allocate frame buffer", FAS_OUT_OF_MEMORY); - } - - fas_context->rgb_frame_buffer = avcodec_alloc_frame (); - if (fas_context->rgb_frame_buffer == NULL) - { - fas_close_video(fas_context); - return private_show_error ("failed to allocate rgb frame buffer", FAS_OUT_OF_MEMORY); - } - - fas_context->gray8_frame_buffer = avcodec_alloc_frame (); - if (fas_context->gray8_frame_buffer == NULL) - { - fas_close_video(fas_context); - return private_show_error ("failed to allocate gray8 frame buffer", FAS_OUT_OF_MEMORY); - } - - fas_context->rgb_buffer = 0; - fas_context->gray8_buffer = 0; - fas_context->rgb_already_converted = FAS_FALSE; - fas_context->gray8_already_converted = FAS_FALSE; - - *context_ptr = fas_context; - - - if (FAS_SUCCESS != fas_step_forward(*context_ptr)) - return private_show_error ("failure decoding first frame", FAS_NO_MORE_FRAMES); - - if (!fas_frame_available(*context_ptr)) - return private_show_error ("couldn't find a first frame (no valid frames in video stream)", FAS_NO_MORE_FRAMES); - - - - return FAS_SUCCESS; -} - -/* fas_close_video */ -fas_error_type fas_close_video (fas_context_ref_type context) -{ - if (NULL == context) - return private_show_error ("NULL context provided for fas_close_video()", FAS_INVALID_ARGUMENT); - - if (!(context->is_video_active)) - { - private_show_warning ("Redundant attempt to close an inactive video"); - return FAS_SUCCESS; - } - - if (context->codec_context) - if (avcodec_find_decoder (context->codec_context->codec_id)) - avcodec_close(context->codec_context); - - if (context->format_context) - avformat_close_input (&context->format_context); - - if (context->rgb_frame_buffer) - av_free (context->rgb_frame_buffer); - - if (context->gray8_frame_buffer) - av_free (context->gray8_frame_buffer); - - if (context->rgb_buffer) - av_free(context->rgb_buffer); - - if (context->gray8_buffer) - av_free(context->gray8_buffer); - - if (context->frame_buffer) - av_free (context->frame_buffer); - - seek_release_table (&(context->seek_table)); - - context->is_video_active = FAS_FALSE; - - free (context); - - return FAS_SUCCESS; -} - - -/* fas_step_forward */ -fas_error_type fas_step_forward (fas_context_ref_type context) -{ - if ((NULL == context) || (FAS_TRUE != context->is_video_active)) { - return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT); - } - - if (!context->is_frame_available) - { - private_show_warning ("tried to advance after end of frames"); - return FAS_SUCCESS; - } - - context->current_frame_index++; - - AVPacket packet; - while (FAS_TRUE) - { - if (av_read_frame(context->format_context, &packet) < 0) - { - /* finished */ - context->is_frame_available = FAS_FALSE; - context->seek_table.completed = seek_true; - return FAS_SUCCESS; - } - - int frameFinished; - if (packet.stream_index == context->stream_idx) - { - context->previous_dts = context->current_dts; - context->current_dts = packet.dts; - - /* seek support: set first_dts */ - if (context->first_dts == AV_NOPTS_VALUE) - context->first_dts = packet.dts; - - /* seek support: set key-packet info to previous packet's dts, when possible */ - /* note this -1 approach to setting the packet is a workaround for a common failure. setting - to 0 would work just incur a huge penalty in videos that needed -1. Might be worth testing. - */ - if (packet.flags & AV_PKT_FLAG_KEY) - { - //fprintf(stderr, "Packet: (F:%d %lld %lld)\n", context->current_frame_index, packet.pts, packet.dts); - - if (context->previous_dts == AV_NOPTS_VALUE) - context->keyframe_packet_dts = packet.dts; - else - context->keyframe_packet_dts = context->previous_dts; - } - - avcodec_decode_video2(context->codec_context, context->frame_buffer, &frameFinished, &packet); - - if (frameFinished) - { - /* seek support: (try to) add entry to seek_table */ - if (context->frame_buffer->key_frame) - { - // fprintf(stderr, "Frame : (PXX F%d: %lld %lld)\n", context->current_frame_index, packet.pts, packet.dts); - - seek_entry_type entry; - entry.display_index = context->current_frame_index; - entry.first_packet_dts = context->keyframe_packet_dts; - entry.last_packet_dts = packet.dts; - - if (fas_get_frame_index(context) == FIRST_FRAME_INDEX) - entry.first_packet_dts = context->first_dts; - - seek_append_table_entry(&context->seek_table, entry); - } - - if (context->current_frame_index - FIRST_FRAME_INDEX + 1 > context->seek_table.num_frames) - context->seek_table.num_frames = context->current_frame_index - FIRST_FRAME_INDEX + 1; - - break; - } - } - - av_free_packet(&packet); - } - - context->rgb_already_converted = FAS_FALSE; - context->gray8_already_converted = FAS_FALSE; - av_free_packet(&packet); - return FAS_SUCCESS; -} - -/* fas_get_frame_index */ - -int fas_get_frame_index (fas_context_ref_type context) -{ - if (NULL == context) - return private_show_error ("NULL context provided for fas_get_frame_index()", FAS_INVALID_ARGUMENT); - - if (FAS_TRUE != context->is_video_active) - return private_show_error ("No video is open for fas_get_frame_index()", FAS_INVALID_ARGUMENT); - - return context->current_frame_index; -} - - -/* fas_get_frame */ - -fas_error_type fas_get_frame (fas_context_ref_type context, fas_raw_image_type *image_ptr) -{ - int buffer_size; - fas_error_type fas_error; - - if (NULL == context || FAS_FALSE == context->is_video_active) - return private_show_error ("null context or inactive video", FAS_INVALID_ARGUMENT); - - if (NULL == image_ptr) - return private_show_error ("null image_ptr on get_frame", FAS_INVALID_ARGUMENT); - - if (!fas_frame_available(context)) - return private_show_error ("no frame available for extraction", FAS_NO_MORE_FRAMES); - - memset (image_ptr, 0, sizeof (fas_raw_image_type)); - - switch (fmt) - { - case PIX_FMT_RGB24: - image_ptr->bytes_per_line = context->codec_context->width * 3; - image_ptr->color_space = FAS_RGB24; - break; - case PIX_FMT_BGR24: - image_ptr->bytes_per_line = context->codec_context->width * 3; - image_ptr->color_space = FAS_BGR24; - break; - case PIX_FMT_ARGB: - image_ptr->bytes_per_line = context->codec_context->width * 4; - image_ptr->color_space = FAS_ARGB32; - break; - case PIX_FMT_ABGR: - image_ptr->bytes_per_line = context->codec_context->width * 4; - image_ptr->color_space = FAS_ABGR32; - break; - case PIX_FMT_YUV420P: - image_ptr->bytes_per_line = (context->codec_context->width * 3) >> 1; - image_ptr->color_space = FAS_YUV420P; - break; - case PIX_FMT_YUYV422: - image_ptr->bytes_per_line = context->codec_context->width * 2; - image_ptr->color_space = FAS_YUYV422; - break; - case PIX_FMT_UYVY422: - image_ptr->bytes_per_line = context->codec_context->width * 2; - image_ptr->color_space = FAS_UYVY422; - break; - case PIX_FMT_YUV422P: - image_ptr->bytes_per_line = context->codec_context->width * 2; - image_ptr->color_space = FAS_YUV422P; - break; - case PIX_FMT_YUV444P: - image_ptr->bytes_per_line = context->codec_context->width * 3; - image_ptr->color_space = FAS_YUV444P; - break; - default: //iinserted TJR - to suppress warnings - break; - } - - buffer_size = image_ptr->bytes_per_line * context->codec_context->height; - - image_ptr->data = (unsigned char *)malloc (buffer_size); - if (NULL == image_ptr->data) - return private_show_error ("unable to allocate space for RGB image", FAS_OUT_OF_MEMORY); - - image_ptr->width = context->codec_context->width; - image_ptr->height = context->codec_context->height; - - - fas_error = private_convert_to_rgb(context); - - int j; - unsigned char *from; - unsigned char *to; - for (j=0;j<context->codec_context->height; j++) - { - from = context->rgb_frame_buffer->data[0] + j*context->rgb_frame_buffer->linesize[0]; - to = image_ptr->data + j*image_ptr->bytes_per_line; - - memcpy(to, from, image_ptr->bytes_per_line); - } - - if (FAS_SUCCESS != fas_error) - return private_show_error ("unable to convert image to RGB", FAS_FAILURE); - - return FAS_SUCCESS; -} - -/* fas_free_frame */ - -void fas_free_frame (fas_raw_image_type image) -{ - if (NULL == image.data) - return; - - free (image.data); - - return; -} - -/* fas_get_seek_table */ -seek_table_type fas_get_seek_table (fas_context_ref_type context) -{ - seek_table_type null_table; - - null_table.array = NULL; - null_table.completed = seek_false; - null_table.num_frames = -1; - null_table.num_entries = 0; - null_table.allocated_size = 0; - - if (NULL == context || FAS_FALSE == context->is_video_active) - return null_table; - - return context->seek_table; -} - -/* fas_put_seek_table */ -fas_error_type fas_put_seek_table (fas_context_ref_type context, seek_table_type table) -{ - if (NULL == context || FAS_FALSE == context->is_video_active) - return private_show_error ("null context or inactive video", FAS_INVALID_ARGUMENT); - - seek_release_table (&context->seek_table); - context->seek_table = seek_copy_table(table); - - return FAS_SUCCESS; -} - -/* private_complete_seek_table */ -fas_error_type private_complete_seek_table (fas_context_ref_type context) -{ - if ((NULL == context) || (FAS_FALSE == context->is_video_active)) - return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT); - - if (context->seek_table.completed) - return FAS_SUCCESS; - - fas_error_type fas_error = fas_seek_to_nearest_key (context, context->seek_table.num_frames + FIRST_FRAME_INDEX - 1); - if (FAS_SUCCESS != fas_error) - return private_show_error("failed when trying to complete seek table (1) (first frame not labeled keyframe?)", fas_error); - - while (fas_frame_available(context)) - { - // printf("%d\n", context->seek_table.num_frames); - fas_step_forward(context); - } - - if (!context->seek_table.completed) - return private_show_error("failed when trying to complete seek table (2)", FAS_SEEK_ERROR); - - return FAS_SUCCESS; -} - -/* fas_seek_to_frame */ -fas_error_type fas_seek_to_frame (fas_context_ref_type context, int target_index) -{ - - fas_error_type fas_error; - - if ((NULL == context) || (FAS_FALSE == context->is_video_active)) - return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT); - - // printf("seeking to %d (from %d)!\n", target_index, context->current_frame_index); - if (target_index == context->current_frame_index) - return FAS_SUCCESS; - - fas_error = fas_seek_to_nearest_key (context, target_index); - - if (fas_error != FAS_SUCCESS) - return private_show_error ("error advancing to key frame before seek", fas_error); - - if (fas_get_frame_index(context) > target_index) - return private_show_error ("error advancing to key frame before seek (index isn't right)", fas_error); - - while (fas_get_frame_index(context) < target_index) - { - if (fas_frame_available(context)) - fas_step_forward(context); - else - return private_show_error ("error advancing to request frame (probably out of range)", FAS_SEEK_ERROR); - } - - - return FAS_SUCCESS; -} - -/* fas_seek_to_nearest_key */ - -fas_error_type fas_seek_to_nearest_key (fas_context_ref_type context, int target_index) -{ - return private_seek_to_nearest_key(context, target_index,0); -} - -/* private_seek_to_nearest_key */ - -fas_error_type private_seek_to_nearest_key (fas_context_ref_type context, int target_index, int offset) -{ - if ((NULL == context) || (FAS_TRUE != context->is_video_active)) - return private_show_error ("invalid or unopened context", FAS_INVALID_ARGUMENT); - - // printf("HERE: from: %d to: %d offset: %d\n", context->current_frame_index, target_index, offset); - fas_error_type fas_error; - seek_entry_type seek_entry; - seek_error_type seek_error = seek_get_nearest_entry (&(context->seek_table), &seek_entry, target_index, offset); - - if (seek_error != seek_no_error) - return private_show_error ("error while searching seek table", FAS_SEEK_ERROR); - - if (seek_entry.display_index == context->current_frame_index) - return FAS_SUCCESS; - - // printf("HERE: from: %d to: %d (%d) offset: %d\n", context->current_frame_index, target_index, seek_entry.display_index, offset); - // printf("trying to seek to %d (%lld->%lld)\n", seek_entry.display_index, seek_entry.first_packet_dts, seek_entry.last_packet_dts); - - // if something goes terribly wrong, return bad current_frame_index - context->current_frame_index = -2; - context->is_frame_available = FAS_TRUE; - - int flags = 0; - if (seek_entry.first_packet_dts <= context->current_dts) - flags = AVSEEK_FLAG_BACKWARD; - - // printf("av_seek_frame: %lld\n", seek_entry.first_packet_dts); - if (av_seek_frame(context->format_context, context->stream_idx, seek_entry.first_packet_dts, flags) < 0) - return private_show_error("seek to keyframe failed", FAS_SEEK_ERROR); - - - avcodec_flush_buffers (context->codec_context); - - fas_error = fas_step_forward (context); - - if (fas_error != FAS_SUCCESS || !context->is_frame_available) - { - // something bad has happened, try previous keyframe - private_show_warning("processing of seeked keyframe failed, trying previous keyframe"); - return private_seek_to_nearest_key(context, target_index, offset + 1); - } - - while (context->current_dts < seek_entry.last_packet_dts) - { - //printf("frame-times: current: %lld target: %lld is_key: %d\n", context->current_dts, seek_entry.last_packet_dts, context->frame_buffer->key_frame); - fas_error = fas_step_forward(context); - if (fas_error != FAS_SUCCESS) - return private_show_error ("unable to process up to target frame (fas_seek_to_frame)", fas_error); - } - - // printf("keyframe vitals: %d looking_for: %lld at: %lld\n", seek_entry.display_index, seek_entry.last_packet_dts, context->current_dts); - if (context->current_dts != seek_entry.last_packet_dts) - { - /* seek to last key-frame, but look for this one */ - private_show_warning("missed keyframe, trying previous keyframe"); - return private_seek_to_nearest_key(context, target_index, offset + 1); - } - - /* Ideally, we could just check if the frame decoded is of the correct time stamp... but... we need several ugly workarounds: - - 1) Some videos have bad keyframes that don't get decoded properly. In this cases, we need to go back a keyframe. - - 2) Other times, none of the frames are labeled keyframes. In these cases, we need to allow seeking to frame 0 - even when it's not labeled as a keyframe. Messy set of conditions. - */ - - if ((!context->frame_buffer->key_frame) && (seek_entry.display_index != 0)) - { - private_show_warning("found keyframe, but not labeled as keyframe, so trying previous keyframe."); - /* seek & look for previous keyframe */ - /* REMOVE FROM TABLE? */ - return private_seek_to_nearest_key(context, seek_entry.display_index - 1, 0); - } - - context->current_frame_index = seek_entry.display_index; - - return FAS_SUCCESS; -} - -/* fas_get_frame_count */ - -int fas_get_frame_count_fast (fas_context_ref_type context) -{ - - if (NULL == context || FAS_FALSE == context->is_video_active) - { - private_show_error ("NULL or invalid context", FAS_INVALID_ARGUMENT); - return -1; - } - - if (context->seek_table.completed == seek_true) - return context->seek_table.num_frames; - - return -1; -} - -int fas_get_frame_count (fas_context_ref_type context) -{ - int fast = fas_get_frame_count_fast(context); - if (fast >= 0) - return fast; - - int current_frame = fas_get_frame_index(context); - - fas_error_type fas_error; - - fas_error = private_complete_seek_table(context); - if (FAS_SUCCESS != fas_error) - { - private_show_error("failed in get_frame_count trying to complete the seek table", fas_error); - return -1; - } - - // seek_show_raw_table(stderr, context->seek_table); - - fas_error = fas_seek_to_frame(context, current_frame); - if (FAS_SUCCESS != fas_error) - { - private_show_error("failed in get_frame_count when trying to seek back to original location", fas_error); - return -1; - } - - fast = fas_get_frame_count_fast(context); - if (fast < 0) - private_show_warning("get_frame_count failed"); - - return fast; -} - -/* fas_frame_available */ - -fas_boolean_type fas_frame_available (fas_context_ref_type context) -{ - if (NULL == context) - { - private_show_error ("NULL context provided for fas_get_frame_index()", FAS_INVALID_ARGUMENT); - return FAS_FALSE; - } - - if (!context->is_video_active) - return FAS_FALSE; - - return context->is_frame_available; -} - - -/* private_show_error */ - -fas_error_type private_show_error (const char *message, fas_error_type error) -{ - if (SHOW_ERROR_MESSAGES) - fprintf (stderr, " ===> ffmpeg_fas: %s\n", message); - return error; -} - -void private_show_warning (const char *message) -{ - if (SHOW_WARNING_MESSAGES) - fprintf (stderr, " ---- ffmpeg_fas: %s\n", message); - return; -} - - -/* private_convert_to_rgb */ - -fas_error_type private_convert_to_rgb (fas_context_ref_type ctx) -{ - if (ctx->rgb_already_converted) - return FAS_SUCCESS; - - - if (ctx->rgb_buffer == 0) - { - int numBytes = avpicture_get_size(fmt, ctx->codec_context->width, - ctx->codec_context->height); - ctx->rgb_buffer = (uint8_t *) av_malloc(numBytes*sizeof(uint8_t)); - avpicture_fill((AVPicture *) ctx->rgb_frame_buffer, ctx->rgb_buffer, fmt, - ctx->codec_context->width, ctx->codec_context->height); - } - // -/* - if (!sws_ctx) { - sws_ctx = sws_getContext(c->width, c->height, AV_PIX_FMT_YUV420P, - c->width, c->height, c->pix_fmt, - sws_flags, NULL, NULL, NULL); - if (!sws_ctx) { - //fprintf(stderr, - // "Could not initialize the conversion context\n"); - exit(1); - } - } -*/ - -//int img_convert ( AVPicture * dst, -//int dst_pix_fmt, -//const AVPicture * src, -//int src_pix_fmt, -//int src_width, -//int src_height -//) - - //maybe tricky to convert: use sws_ - sws_scale(Sctx, // sws context - ctx->frame_buffer->data, // src slice - ctx->frame_buffer->linesize, // src stride - 0, // src slice origin y - ctx->frame_buffer->height, // src slice height - ctx->rgb_frame_buffer->data, // dst - ctx->rgb_frame_buffer->linesize ); // dst stride - //instead of - //if (img_convert((AVPicture *) ctx->rgb_frame_buffer, fmt, (AVPicture *) ctx->frame_buffer, - // ctx->codec_context->pix_fmt, - // ctx->codec_context->width, ctx->codec_context->height) < 0) - // private_show_error("error converting to rgb", FAS_DECODING_ERROR); - - ctx->rgb_already_converted = FAS_TRUE; - - return FAS_SUCCESS; -} - - -/* private_convert_to_gray8 */ -/* -fas_error_type private_convert_to_gray8 (fas_context_ref_type ctx) -{ - if (ctx->gray8_already_converted) - return FAS_SUCCESS; - - if (ctx->gray8_buffer == 0) - { - int numBytes = avpicture_get_size(PIX_FMT_GRAY8, ctx->codec_context->width, - ctx->codec_context->height); - ctx->gray8_buffer = (uint8_t *) av_malloc(numBytes*sizeof(uint8_t)); - avpicture_fill((AVPicture *) ctx->gray8_frame_buffer, ctx->gray8_buffer, PIX_FMT_GRAY8, - ctx->codec_context->width, ctx->codec_context->height); - } - - if (img_convert((AVPicture *) ctx->gray8_frame_buffer, PIX_FMT_GRAY8, (AVPicture *) ctx->frame_buffer, - ctx->codec_context->pix_fmt, - ctx->codec_context->width, ctx->codec_context->height) < 0) - private_show_error("error converting to gray8", FAS_DECODING_ERROR); - - ctx->gray8_already_converted = FAS_TRUE; - - return FAS_SUCCESS; -} -*/ - -int fas_get_current_width(fas_context_ref_type context) -{ - return context->codec_context->width; -} - -int fas_get_current_height(fas_context_ref_type context) -{ - return context->codec_context->height; -} - -unsigned long long fas_get_frame_duration(fas_context_ref_type context) -{ - if (context->format_context->streams[context->stream_idx]->time_base.den != context->format_context->streams[context->stream_idx]->r_frame_rate.num - || context->format_context->streams[context->stream_idx]->time_base.num != context->format_context->streams[context->stream_idx]->r_frame_rate.den) - { - double frac = (double)(context->format_context->streams[context->stream_idx]->r_frame_rate.den) / (double)(context->format_context->streams[context->stream_idx]->r_frame_rate.num); - return (unsigned long long)(frac*10000000.); - } - else - { - return (unsigned long long)(((double)(context->format_context->streams[context->stream_idx]->time_base.num)) - /((double)(context->format_context->streams[context->stream_idx]->time_base.den))*10000000.); - } -} - -fas_error_type fas_fill_gray8_ptr(fas_context_ref_type context, unsigned char *y) -{ - /* this conversion also seems to screw up sometimes -- pal8 -> gray8? legodragon.avi */ - //if (private_convert_to_gray8(context) != FAS_SUCCESS) TJR commented out - // return FAS_FAILURE; - - int width = context->codec_context->width; - int height = context->codec_context->height; - int i; - for (i=0;i < height; i++) - memcpy(y + width * i, context->gray8_frame_buffer->data[0] + context->gray8_frame_buffer->linesize[0] * i, width); - - return FAS_SUCCESS; -} - -fas_error_type fas_fill_420p_ptrs (fas_context_ref_type context, unsigned char *y, unsigned char *u, unsigned char *v) -{ - AVFrame *p = context->frame_buffer; - - /* 411p to 420p conversion fails!? ... so i left this -ldb */ - if (context->codec_context->pix_fmt != PIX_FMT_YUV420P) - return FAS_FAILURE; - - int width = context->codec_context->width; - int height = context->codec_context->height; - int i; - for (i=0;i < height / 2; i++) - { - memcpy(y + width * (2*i) , p->data[0] + p->linesize[0] * (2*i) , width); - memcpy(y + width * (2*i + 1), p->data[0] + p->linesize[0] * (2*i + 1), width); - memcpy(u + width / 2 * i, p->data[1] + p->linesize[1] * i, width / 2); - memcpy(v + width / 2 * i, p->data[2] + p->linesize[2] * i, width / 2); - } - - return FAS_SUCCESS; -} - diff --git a/rotord/src/ffmpeg_fas.h b/rotord/src/ffmpeg_fas.h deleted file mode 100644 index 0c51103..0000000 --- a/rotord/src/ffmpeg_fas.h +++ /dev/null @@ -1,130 +0,0 @@ -/***************************************************************************** - * Copyright 2008. Pittsburgh Pattern Recognition, Inc. - * - * This file is part of the Frame Accurate Seeking extension library to - * ffmpeg (ffmpeg-fas). - * - * ffmpeg-fas is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * The ffmpeg-fas library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -#ifndef FFMPEG_FAS_H -#define FFMPEG_FAS_H - -/* If C++ then we need to __extern "C". Compiler defines __cplusplus */ -#ifdef __cplusplus -#define __extern extern "C" -#else -#define __extern extern -#endif - - -#ifndef UINT64_C -#define UINT64_C(c) (c ## ULL) -#endif - -#include "seek_indices.h" -#include <libswscale/swscale.h> - - -static struct SwsContext *Sctx; -static int sws_flags = SWS_BICUBIC; - - -typedef enum -{ - FAS_GRAY8 = 1, - FAS_RGB24 = 2, - FAS_BGR24 = 3, - FAS_ARGB32 = 4, - FAS_ABGR32 = 5, - FAS_YUV420P = 6, - FAS_YUYV422 = 7, - FAS_UYVY422 = 8, - FAS_YUV422P = 9, - FAS_YUV444P = 10, -} fas_color_space_type; - -typedef struct -{ - unsigned char *data; - int width; - int height; - int bytes_per_line; - fas_color_space_type color_space; -} fas_raw_image_type; - - -/********************************************************************** - * Video IO Types - **********************************************************************/ - -typedef struct fas_context_struct* fas_context_ref_type; - -typedef enum -{ - FAS_SUCCESS, - FAS_FAILURE, - FAS_INVALID_ARGUMENT, - FAS_OUT_OF_MEMORY, - FAS_UNSUPPORTED_FORMAT, - FAS_UNSUPPORTED_CODEC, - FAS_NO_MORE_FRAMES, - FAS_DECODING_ERROR, - FAS_SEEK_ERROR, -} fas_error_type; - -typedef enum -{ - FAS_FALSE = 0, - FAS_TRUE = 1 -} fas_boolean_type; - - -__extern void fas_initialize (fas_boolean_type logging, fas_color_space_type format); -__extern void fas_set_format (fas_color_space_type format); - -__extern fas_error_type fas_open_video (fas_context_ref_type *context_ptr, char *file_path); -__extern fas_error_type fas_close_video (fas_context_ref_type context); - -__extern char* fas_error_message (fas_error_type error); - -__extern fas_boolean_type fas_frame_available (fas_context_ref_type context); -__extern int fas_get_frame_index (fas_context_ref_type context); -__extern fas_error_type fas_step_forward (fas_context_ref_type context); - -__extern fas_error_type fas_get_frame (fas_context_ref_type context, fas_raw_image_type *image_ptr); -__extern void fas_free_frame (fas_raw_image_type image); - -__extern fas_error_type fas_seek_to_nearest_key (fas_context_ref_type context, int target_index); -__extern fas_error_type fas_seek_to_frame (fas_context_ref_type context, int target_index); - -__extern int fas_get_frame_count (fas_context_ref_type context); -__extern int fas_get_frame_count_fast (fas_context_ref_type context); - -__extern fas_error_type fas_put_seek_table (fas_context_ref_type context, seek_table_type table); -__extern seek_table_type fas_get_seek_table (fas_context_ref_type context); - -/* will extract raw 420p if the video is in that format -- needs to be alloced ahead of time*/ -__extern fas_error_type fas_fill_420p_ptrs (fas_context_ref_type context, unsigned char *y, unsigned char *u, unsigned char *v); - -/* will extract gray8 data from movie (will convert to ensure you get it) -- need to be alloc'ed ahead of time*/ -__extern fas_error_type fas_fill_gray8_ptr(fas_context_ref_type context, unsigned char *y); - -__extern int fas_get_current_width(fas_context_ref_type context); -__extern int fas_get_current_height(fas_context_ref_type context); - -__extern unsigned long long fas_get_frame_duration(fas_context_ref_type context); - -#endif diff --git a/rotord/src/graph.cpp b/rotord/src/graph.cpp index 2e89a4c..5487717 100644 --- a/rotord/src/graph.cpp +++ b/rotord/src/graph.cpp @@ -279,6 +279,7 @@ bool Graph::parseJson(string &data,string &media_path){ } //we know the json validates so clear the existing graph clear(); + Node_factory factory; check_audio(root["audio"].asString(),media_path); init(root["ID"].asString(),root["description"].asString()); Json::Value jnodes = root["nodeDefinitions"]; @@ -394,6 +395,7 @@ bool Graph::parseJson(string &data,string &media_path){ } bool Graph::parseXml(string media_path){ clear(); + Node_factory factory; check_audio(xml.getAttribute("patchbay","audio","",0),media_path); init(xml.getAttribute("patchbay","ID","",0),xml.getValue("patchbay","",0)); if(xml.pushTag("patchbay")) { diff --git a/rotord/src/graph.h b/rotord/src/graph.h index d614b3b..b2132b9 100644 --- a/rotord/src/graph.h +++ b/rotord/src/graph.h @@ -61,7 +61,6 @@ namespace Rotor { bool cancelled; float progress; private: - Node_factory factory; int outW,outH; }; diff --git a/rotord/src/libavwrapper.cpp b/rotord/src/libavwrapper.cpp index b7b5688..321725e 100644 --- a/rotord/src/libavwrapper.cpp +++ b/rotord/src/libavwrapper.cpp @@ -80,8 +80,9 @@ void libav::maybeInitFFMpegLib() { if (b_is_one_time_inited) return; - av_register_all(); - avcodec_register_all(); + FFMS_Init(0, 0); //should do for all + //av_register_all(); + //avcodec_register_all(); avformat_network_init(); b_is_one_time_inited = true; } @@ -556,7 +557,56 @@ bool libav::decoder::avtry(int result, const std::string& msg) { return true; } + void libav::ffms2_decoder::cleanup(){ + if (loaded) { + mutex.lock(); + FFMS_DestroyVideoSource(videosource); + mutex.unlock(); + loaded=false; + } +} +bool libav::ffms2_decoder::open(const std::string& filename){ + mutex.lock(); + loaded=false; + FFMS_Index *index = FFMS_MakeIndex(filename.c_str(), 0, 0, NULL, NULL, FFMS_IEH_ABORT, NULL, NULL, &errinfo); + if (index == NULL) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + mutex.unlock(); + return false; + } + int trackno = FFMS_GetFirstTrackOfType(index, FFMS_TYPE_VIDEO, &errinfo); + if (trackno < 0) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + mutex.unlock(); + return false; + } + videosource = FFMS_CreateVideoSource(filename.c_str(), trackno, index, 1, FFMS_SEEK_NORMAL, &errinfo); + if (videosource == NULL) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + mutex.unlock(); + return false; + } + FFMS_DestroyIndex(index); + videoprops = FFMS_GetVideoProperties(videosource); + const FFMS_Frame *propframe = FFMS_GetFrame(videosource, 0, &errinfo); + w=propframe->EncodedWidth; + h=propframe->EncodedHeight; + //propframe->EncodedPixelFormat; + + if (FFMS_SetOutputFormatV2(videosource, pixfmts, propframe->EncodedWidth, propframe->EncodedHeight, FFMS_RESIZER_BICUBIC, &errinfo)) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + mutex.unlock(); + return false; + } + int framenumber = 0; /* valid until next call to FFMS_GetFrame* on the same video object */ + + + std::cerr<<"ffmpegsource: successfully opened "<<filename<<std::endl; + loaded=true; + mutex.unlock(); + return loaded; +} /////////////////////////// // encoder methods // @@ -1245,7 +1295,7 @@ void libav::exporter::open_video(AVFormatContext *oc, AVCodec *codec, AVStream * AVFrame *frame = avcodec_alloc_frame(); int got_packet, ret; - av_init_packet(&pkt); + //av_init_packet(&pkt); 111013 NOT NECESSARY c = st->codec; //get_audio_frame(samples, audio_input_frame_size, c->channels); @@ -1406,7 +1456,7 @@ void libav::exporter::open_video(AVFormatContext *oc, AVCodec *codec, AVStream * if (oc->oformat->flags & AVFMT_RAWPICTURE) { // Raw video case - directly store the picture in the packet // AVPacket pkt; - av_init_packet(&pkt); + //av_init_packet(&pkt); ///removed 101013 NOT NECESSARY pkt.flags |= AV_PKT_FLAG_KEY; pkt.stream_index = st->index; @@ -1418,7 +1468,7 @@ void libav::exporter::open_video(AVFormatContext *oc, AVCodec *codec, AVStream * } else { AVPacket pkt = { 0 }; int got_packet; - av_init_packet(&pkt); + //av_init_packet(&pkt); ///removed 101013 NOT NECESSARY // encode the image // diff --git a/rotord/src/libavwrapper.h b/rotord/src/libavwrapper.h index d30ea95..870815f 100644 --- a/rotord/src/libavwrapper.h +++ b/rotord/src/libavwrapper.h @@ -69,6 +69,8 @@ extern "C" { #include <math.h> #include <vector> +#include <ffms.h> + namespace libav { @@ -154,6 +156,68 @@ namespace libav { }; + class ffms2_decoder + { + public: + ffms2_decoder(){ + maybeInitFFMpegLib(); + pixfmts[0] = FFMS_GetPixFmt("rgb24"); + pixfmts[1] = -1; + h=0; + w=0; + videosource=NULL; + loaded=false; + errinfo.Buffer = errmsg; + errinfo.BufferSize = sizeof(errmsg); + errinfo.ErrorType = FFMS_ERROR_SUCCESS; + errinfo.SubType = FFMS_ERROR_SUCCESS; + } + ~ffms2_decoder(){ + cleanup(); + } + void cleanup(); + bool open(const std::string& filename); + float getFrameRate(){ + if (loaded) return (((float)videoprops->FPSNumerator)/((float)videoprops->FPSDenominator)); + else return -1.0f; + } + int getNumberOfFrames(){ + if (loaded) return videoprops->NumFrames; + else return -1; + } + int getNumberOfChannels(){ + return 3; //this is what we convert to + } + int getWidth(){ + return w; + } + int getHeight(){ + return h; + } + bool fetchFrame(int width,int height,int wanted){ + if (FFMS_SetOutputFormatV2(videosource, pixfmts, width, height, FFMS_RESIZER_BICUBIC, &errinfo)) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + return false; + } + frame = FFMS_GetFrame(videosource, wanted%videoprops->NumFrames, &errinfo); + if (frame == NULL) { + std::cerr<<"ffmpegsource: "<<errinfo.Buffer<<std::endl; + return false; + } + return true; + + } + + FFMS_VideoSource *videosource; + FFMS_VideoProperties *videoprops; + FFMS_Frame *frame; + FFMS_ErrorInfo errinfo; + char errmsg[1024]; + int pixfmts[2]; + bool loaded; + int h,w; + }; + /* // TODO - finish refactoring based on // http://svn.gnumonks.org/trunk/21c3-video/ffmpeg/ffmpeg-0.4.9-pre1/output_example.c diff --git a/rotord/src/ofUtils.o b/rotord/src/ofUtils.o Binary files differnew file mode 100644 index 0000000..d31a12b --- /dev/null +++ b/rotord/src/ofUtils.o diff --git a/rotord/src/private_errors.h b/rotord/src/private_errors.h deleted file mode 100644 index 9369ae3..0000000 --- a/rotord/src/private_errors.h +++ /dev/null @@ -1,32 +0,0 @@ -/***************************************************************************** - * Copyright 2008. Pittsburgh Pattern Recognition, Inc. - * - * This file is part of the Frame Accurate Seeking extension library to - * ffmpeg (ffmpeg-fas). - * - * ffmpeg-fas is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * The ffmpeg-fas library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -#ifndef FAS_PRIVATE_ERROR_H -#define FAS_PRIVATE_ERROR_H - -#if defined( _WIN32 ) && defined( STATIC_DLL ) -static int SHOW_ERROR_MESSAGES; -static int SHOW_WARNING_MESSAGES; -#else -int SHOW_ERROR_MESSAGES; -int SHOW_WARNING_MESSAGES; -#endif /* _WIN32 && STATIC_DLL */ -#endif diff --git a/rotord/src/rendercontext.h b/rotord/src/rendercontext.h index f15ca31..b525a07 100644 --- a/rotord/src/rendercontext.h +++ b/rotord/src/rendercontext.h @@ -103,7 +103,6 @@ namespace Rotor { Audio_thumbnailer *audio_thumb; Graph graph; - Node_factory factory; float output_framerate; }; diff --git a/rotord/src/rotor.cpp b/rotord/src/rotor.cpp index ee18dbd..d26cdec 100644 --- a/rotord/src/rotor.cpp +++ b/rotord/src/rotor.cpp @@ -80,7 +80,7 @@ float Parameter::get(const Time_spec& time){ //gets input and updates variable return value; } -bool Video_loader::load(const string &_filename){ +bool _Video_loader::load(const string &_filename){ Logger& logger = Logger::get("Rotor"); if (isLoaded) { player.cleanup(); ///should be in decoder class? @@ -102,7 +102,7 @@ bool Video_loader::load(const string &_filename){ return false; } -Image* Video_loader::output(const Frame_spec &frame){ +Image* _Video_loader::output(const Frame_spec &frame){ if (isLoaded){ //this approach is running into the inability to seek when requesting playback speed > 1. diff --git a/rotord/src/rotor.h b/rotord/src/rotor.h index eba5be1..ff8675a 100644 --- a/rotord/src/rotor.h +++ b/rotord/src/rotor.h @@ -29,7 +29,6 @@ Definitions of base classes and types for rotor rendering graph #include "utils.h" #include "cvimage.h" #include "libavwrapper.h" -#include "ffmpeg-fas_wrapper.h" //using namespace cv; namespace Rotor { @@ -879,6 +878,33 @@ namespace Rotor { }; #define VIDEOFRAMES_frame 1 #define VIDEOFRAMES_blend 2 + class _Video_loader: public Image_node { + public: + _Video_loader(){ + create_parameter("speed","number","video playback speed","Speed",1.0f,0.0f,0.0f); + create_parameter("framerate","number","framerate override","Frame rate",0.0f,0.0f,0.0f); + create_attribute("filename","name of video file to load","File name",""); + create_attribute("mode","frame mode","Mode","frame",{"frame","blend"}); + title="Video loader"; + description="Loads a video file"; + }; + _Video_loader(map<string,string> &settings): _Video_loader() { + base_settings(settings); + isLoaded=false; + if (attributes["filename"]->value!="") { + load(find_setting(settings,"media_path","")+attributes["filename"]->value); + } + lastframe=0; + }; + ~_Video_loader(){}; + bool load(const string &filename); + Image *output(const Frame_spec &frame); + _Video_loader* clone(map<string,string> &_settings) { return new _Video_loader(_settings);}; + bool isLoaded; + private: + libav::decoder player; + int lastframe; + }; class Video_loader: public Image_node { public: Video_loader(){ @@ -898,12 +924,49 @@ namespace Rotor { lastframe=0; }; ~Video_loader(){}; - bool load(const string &filename); - Image *output(const Frame_spec &frame); + bool load(const string &filename){ + Poco::Logger& logger = Poco::Logger::get("Rotor"); + if (isLoaded) { + player.cleanup(); ///should be in decoder class? + isLoaded=false; + } + isLoaded=player.open(filename); + if (isLoaded){ + logger.information("Video_loader loaded "+filename+": "\ + +toString(player.getNumberOfFrames())+" frames, "\ + +toString(player.getFrameRate())+" fps, "\ + +toString(player.getWidth())+"x"+toString(player.getHeight())\ + +", channels:"+toString(player.getNumberOfChannels())); + return true; + } + logger.error("Video_loader failed to load "+filename); + return false; + } + Image *output(const Frame_spec &frame){ + if (isLoaded){ + float clipframerate=(parameters["framerate"]->value==0.0f?player.getFrameRate():parameters["framerate"]->value); + float clipspeed=(clipframerate/frame.framerate)*parameters["speed"]->value; + int wanted=(((int) ((frame.time*frame.framerate)+0.5))%max(1,player.getNumberOfFrames()-1)); + if (wanted!=lastframe){ + if (!player.fetchFrame(frame.w,frame.h,wanted)) { //seek fail + Poco::Logger& logger = Poco::Logger::get("Rotor"); + logger.error("Video_loader failed to seek frame "+toString(wanted)+" of "+attributes["filename"]->value); + + if (image.w>0) return ℑ //just return the previous frame if possible + else return nullptr; + } + image.setup_fromRGB(frame.w,frame.h,player.frame->Data[0],player.frame->Linesize[0]-(frame.w*3)); + lastframe=wanted; + } + return ℑ + } + return nullptr; + }; Video_loader* clone(map<string,string> &_settings) { return new Video_loader(_settings);}; bool isLoaded; private: - libav::decoder player; + //ffmpegsource::decoder player; + libav::ffms2_decoder player; int lastframe; }; class Video_output: public Image_node { diff --git a/rotord/src/seek_indices.c b/rotord/src/seek_indices.c deleted file mode 100644 index cb877c3..0000000 --- a/rotord/src/seek_indices.c +++ /dev/null @@ -1,319 +0,0 @@ -/***************************************************************************** - * Copyright 2008. Pittsburgh Pattern Recognition, Inc. - * - * This file is part of the Frame Accurate Seeking extension library to - * ffmpeg (ffmpeg-fas). - * - * ffmpeg-fas is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * The ffmpeg-fas library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -#include <stdlib.h> -#include <stdio.h> -#include <stdint.h> -#include <string.h> - -#include "seek_indices.h" -#include "private_errors.h" - -/**** Defines *****************************************************************/ - -#define DEFAULT_INITIAL_SIZE 100 - -static seek_error_type private_show_error (const char *message, seek_error_type error); -static seek_error_type private_resize_table (seek_table_type *table, int new_size); - - -/* - * seek_init_table - */ - -int compare_seek_tables(seek_table_type t1, seek_table_type t2) -{ - int i; - - // printf("n_entries=(%d %d)\n", t1.num_entries, t2.num_entries); - - if (t1.num_entries != t2.num_entries) - return 0; - - if (t1.completed != t2.completed) - return 0; - - if (t1.num_frames != t2.num_frames) - return 0; - - for (i=0;i<t1.num_entries;i++) - { - // printf("(%d %d) (%lld %lld) (%lld %lld)\n", - // t1.array[i].display_index, t2.array[i].display_index, - // t1.array[i].decode_time, t2.array[i].decode_time, - // t1.array[i].display_time, t2.array[i].display_time); - if ((t1.array[i].display_index != t2.array[i].display_index) || - (t1.array[i].last_packet_dts != t2.array[i].last_packet_dts) || - (t1.array[i].first_packet_dts != t2.array[i].first_packet_dts)) - return 0; - } - - return 1; -} - -seek_table_type seek_init_table (int initial_size) -{ - seek_table_type table; - - if (initial_size < 0) - initial_size = DEFAULT_INITIAL_SIZE; - - table.num_entries = 0; - table.num_frames = -1; - table.completed = seek_false; - - table.array = (seek_entry_type *)malloc (initial_size * sizeof(seek_entry_type)); - - if (NULL == table.array) - table.allocated_size = 0; - else - table.allocated_size = initial_size; - - return table; -} - -/* - * seek_release_table - */ - -void seek_release_table (seek_table_type *table) -{ - table->num_entries = 0; - table->num_frames = -1; - table->completed = seek_false; - - if (NULL == table || NULL == table->array) - return; - - free (table->array); - return; -} - -/* - * seek_copy_table - */ - -seek_table_type seek_copy_table (seek_table_type source) -{ - seek_table_type dest; - dest.num_entries = source.num_entries; - dest.num_frames = source.num_frames; - dest.completed = source.completed; - - if (NULL == source.array) - { - dest.array = NULL; - dest.allocated_size = 0; - return dest; - } - - dest.array = (seek_entry_type *)malloc (source.num_entries * sizeof(seek_entry_type)); - - if (NULL == dest.array) - { - dest.array = NULL; - dest.allocated_size = 0; - return dest; - } - - dest.allocated_size = source.num_entries; - - int i; - for (i=0;i<source.num_entries;i++) - dest.array[i] = source.array[i]; - - return dest; -} - -seek_error_type seek_append_table_entry (seek_table_type *table, seek_entry_type entry) -{ - - if (NULL == table || NULL == table->array) - return private_show_error("null or invalid seek table", seek_bad_argument); - - if (table->num_entries != 0) - if (table->array[table->num_entries - 1].display_index >= entry.display_index) - return seek_no_error; - - if (table->num_entries == table->allocated_size) - { - seek_error_type error = private_resize_table (table, table->num_entries * 2); - if (error != seek_no_error) - return private_show_error ("unable to resize seek table", error); - } - - table->array[table->num_entries] = entry; - table->num_entries++; - - return seek_no_error; -} - -/* - * seek_get_nearest_entry - */ - -seek_error_type seek_get_nearest_entry (seek_table_type *table, seek_entry_type *entry, int display_index, int offset) -{ - /* using offset>0 returns a modified seek_entry that sets the 'time-to-seek' to be $offset keyframes in the past. - */ - - if (NULL == table || NULL == table->array || table->num_entries <= 0) { - return private_show_error ("NULL or invalid seek table", seek_bad_argument); - } - - if (NULL == entry) { - return private_show_error ("NULL entry buffer (for return)", seek_bad_argument); - } - - if (display_index < table->array[0].display_index) - return private_show_error ("tried to seek to frame index before first frame", seek_bad_argument); - - int i; - for (i=0; i < table->num_entries; i++) - if (table->array[i].display_index > display_index) - break; - - i = i-1; - - if (i<offset) /* target was lower than first element (including offset) */ - return private_show_error ("target index out of table range (too small)", seek_bad_argument); - - *entry = table->array[i]; - (*entry).first_packet_dts = table->array[i-offset].first_packet_dts; - - return seek_no_error; -} - - -/* read raw file */ -seek_table_type read_table_file(char *name) -{ - seek_table_type ans = { NULL, (seek_boolean_type) 0, (seek_boolean_type) 0 }; - - FILE *table_file = fopen(name, "r"); - if (table_file == NULL) - return ans; - - int completed_flag; - fscanf(table_file, "%d %d %d\n", &ans.num_frames, &ans.num_entries, &completed_flag); - - if (completed_flag == 1) - ans.completed = seek_true; - else - ans.completed = seek_false; - - ans.allocated_size = ans.num_entries; - ans.array = (seek_entry_type*) malloc (ans.allocated_size * sizeof(seek_entry_type)); - - int i; - for (i=0;i<ans.num_entries;i++) - fscanf(table_file, "%d %lld %lld\n", &(ans.array[i].display_index), &(ans.array[i].first_packet_dts), &(ans.array[i].last_packet_dts)); - - fclose(table_file); - return ans; -} - -seek_error_type seek_show_raw_table (FILE* file, seek_table_type table) -{ - seek_entry_type *entry; - int index; - - if (NULL == table.array || table.num_entries <= 0) - return private_show_error ("NULL or invalid seek table", seek_bad_argument); - - int completed_flag = 0; - if (table.completed == seek_true) - completed_flag = 1; - - fprintf(file, "%d %d %d\n", table.num_frames, table.num_entries, completed_flag); - for (index = 0; index < table.num_entries; index++) - { - entry = &(table.array[index]); - - fprintf (file, "%d %lld %lld\n", entry->display_index, entry->first_packet_dts, entry->last_packet_dts); - } - return seek_no_error; -} - -seek_error_type seek_show_table (seek_table_type table) -{ - seek_entry_type *entry; - int index; - - if (NULL == table.array || table.num_entries <= 0) { - return private_show_error ("NULL or invalid seek table", seek_bad_argument); - } - - int completed_flag = 0; - if (table.completed == seek_true) - completed_flag = 1; - - fprintf (stderr, "--- Seek Table Dump ---\n"); - fprintf (stderr, "n_frames: %d n_entries: %d completed: %d\n",table.num_frames, table.num_entries, completed_flag); - for (index = 0; index < table.num_entries; index++) - { - entry = &(table.array[index]); - - fprintf (stderr, " %04d --> %08lld (%08lld)\n", entry->display_index, entry->first_packet_dts, entry->last_packet_dts); - } - - fprintf (stderr, "-----------------------\n"); - - return seek_no_error; -} - -/* - * private_show_error - */ - -static seek_error_type private_show_error (const char *message, seek_error_type error) -{ - if (SHOW_ERROR_MESSAGES) - fprintf (stderr, " ===> seek_indices: %s\n", message); - - return error; -} - -/* - * private_resize_table - */ - -static seek_error_type private_resize_table (seek_table_type *table, int new_size) -{ - seek_entry_type *new_array = NULL; - - if (table == NULL || new_size < 0) { - return private_show_error ("invalid argument for private_resize_table()", seek_malloc_failed); - } - - new_array = (seek_entry_type *)malloc (sizeof (seek_entry_type) * new_size); - if (NULL == new_array) { - return private_show_error ("unable to allocate more space for table", seek_malloc_failed); - } - - memcpy (new_array, table->array, table->allocated_size * sizeof (seek_entry_type)); - free (table->array); - - table->allocated_size = new_size; - table->array = new_array; - - return seek_no_error; -} diff --git a/rotord/src/seek_indices.h b/rotord/src/seek_indices.h deleted file mode 100644 index e908979..0000000 --- a/rotord/src/seek_indices.h +++ /dev/null @@ -1,94 +0,0 @@ -/***************************************************************************** - * Copyright 2008. Pittsburgh Pattern Recognition, Inc. - * - * This file is part of the Frame Accurate Seeking extension library to - * ffmpeg (ffmpeg-fas). - * - * ffmpeg-fas is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 3 of the License, or (at your - * option) any later version. - * - * The ffmpeg-fas library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the ffmpeg-fas library. If not, see <http://www.gnu.org/licenses/>. - * - ******************************************************************************/ - -#ifndef FAS_SEEK_INDICES_H -#define FAS_SEEK_INDICES_H - -#include <stdint.h> -#include <stdio.h> - -/* If C++ then we need to __extern "C". Compiler defines __cplusplus */ -#ifdef __cplusplus -#define __extern extern "C" -#else -#define __extern extern -#endif - - -/********************************************************************** - * Seek Table Types - **********************************************************************/ - -typedef enum -{ - seek_no_error, - seek_unknown_error, - seek_bad_argument, - seek_malloc_failed, -} seek_error_type; - -typedef enum -{ - seek_false = 0, - seek_true = 1 -} seek_boolean_type; - -typedef struct -{ - int display_index; - int64_t first_packet_dts; - int64_t last_packet_dts; -} seek_entry_type; - -typedef struct -{ - seek_entry_type *array; - seek_boolean_type completed; - int num_frames; // total number of frames - int num_entries; // ie, number of seek-points (keyframes) - int allocated_size; -} seek_table_type; - - - -/********************************************************************** - * Seek Table Functions - **********************************************************************/ - - -__extern seek_table_type seek_init_table (int initial_size); -__extern void seek_release_table (seek_table_type *table); - -__extern seek_table_type seek_copy_table (seek_table_type source); -__extern int compare_seek_tables(seek_table_type t1, seek_table_type t2); - -__extern seek_error_type seek_append_table_entry (seek_table_type *table, seek_entry_type entry); - -__extern seek_error_type seek_get_nearest_entry (seek_table_type *table, seek_entry_type *entry, int display_index, int offset); - -__extern seek_error_type seek_show_table (seek_table_type table); /* human readable */ -__extern seek_error_type seek_show_raw_table (FILE *file, seek_table_type table); - -__extern seek_table_type read_table_file(char *name); /* read raw file */ - -#endif - -/**** End of File *****************************************************/ |
