Commit 76662540b15b649e8cabe14077c60a15da373a54

Authored by Ben Klein
2 parents 7a9129f6 2e0e1dd9

Merge pull request #337 from biometrics/keyframes

keyframes gallery implemented with LibAV
openbr/plugins/cmake/libav.cmake 0 → 100644
  1 +set(BR_WITH_LIBAV OFF CACHE BOOL "Build with LibAV")
  2 +
  3 +if(${BR_WITH_LIBAV})
  4 + find_package(LibAV REQUIRED)
  5 + include_directories(${LIBAV_INCLUDE_DIR})
  6 + set(BR_THIRDPARTY_LIBS ${BR_THIRDPARTY_LIBS} ${LIBAV_LIBRARIES})
  7 + set(BR_THIRDPARTY_SRC ${BR_THIRDPARTY_SRC} plugins/gallery/keyframes.cpp)
  8 +
  9 + foreach(LIBAV_LIB ${LIBAV_LIBRARIES})
  10 + install(FILES ${LIBAV_LIB} DESTINATION lib)
  11 + endforeach()
  12 +endif()
openbr/plugins/gallery/keyframes.cpp 0 → 100644
  1 +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2 + * Copyright 2012 The MITRE Corporation *
  3 + * *
  4 + * Licensed under the Apache License, Version 2.0 (the "License"); *
  5 + * you may not use this file except in compliance with the License. *
  6 + * You may obtain a copy of the License at *
  7 + * *
  8 + * http://www.apache.org/licenses/LICENSE-2.0 *
  9 + * *
  10 + * Unless required by applicable law or agreed to in writing, software *
  11 + * distributed under the License is distributed on an "AS IS" BASIS, *
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
  13 + * See the License for the specific language governing permissions and *
  14 + * limitations under the License. *
  15 + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  16 +
  17 +#include <openbr/plugins/openbr_internal.h>
  18 +#include <openbr/core/qtutils.h>
  19 +#include <openbr/core/opencvutils.h>
  20 +
  21 +extern "C"
  22 +{
  23 +#include <libavcodec/avcodec.h>
  24 +#include <libavformat/avformat.h>
  25 +#include <libavutil/avutil.h>
  26 +#include <libswscale/swscale.h>
  27 +}
  28 +
  29 +using namespace cv;
  30 +
  31 +namespace br
  32 +{
  33 +
  34 +/*!
  35 + * \ingroup galleries
  36 + * \brief Read key frames of a video with LibAV
  37 + * \author Ben Klein \cite bhklein
  38 + */
  39 +class keyframesGallery : public Gallery
  40 +{
  41 + Q_OBJECT
  42 +
  43 +public:
  44 + int64_t idx;
  45 +
  46 + keyframesGallery()
  47 + {
  48 + av_register_all();
  49 + avformat_network_init();
  50 + avFormatCtx = NULL;
  51 + avCodecCtx = NULL;
  52 + avSwsCtx = NULL;
  53 + avCodec = NULL;
  54 + frame = NULL;
  55 + cvt_frame = NULL;
  56 + buffer = NULL;
  57 + opened = false;
  58 + streamID = -1;
  59 + fps = 0.f;
  60 + time_base = 0.f;
  61 + idx = 0;
  62 + }
  63 +
  64 + ~keyframesGallery()
  65 + {
  66 + release();
  67 + }
  68 +
  69 + virtual void deferredInit()
  70 + {
  71 + if (avformat_open_input(&avFormatCtx, QtUtils::getAbsolutePath(file.name).toStdString().c_str(), NULL, NULL) != 0) {
  72 + qFatal("Failed to open %s for reading.", qPrintable(file.name));
  73 + } else if (avformat_find_stream_info(avFormatCtx, NULL) < 0) {
  74 + qFatal("Failed to read stream info for %s.", qPrintable(file.name));
  75 + } else {
  76 + for (unsigned int i=0; i<avFormatCtx->nb_streams; i++) {
  77 + if (avFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
  78 + streamID = i;
  79 + break;
  80 + }
  81 + }
  82 + }
  83 +
  84 + if (streamID == -1)
  85 + qFatal("Failed to find video stream for %s", qPrintable(file.name));
  86 +
  87 + avCodecCtx = avFormatCtx->streams[streamID]->codec;
  88 + avCodec = avcodec_find_decoder(avCodecCtx->codec_id);
  89 + if (avCodec == NULL)
  90 + qFatal("Unsupported codec for %s!", qPrintable(file.name));
  91 +
  92 + if (avcodec_open2(avCodecCtx, avCodec, NULL) < 0)
  93 + qFatal("Could not open codec for file %s", qPrintable(file.name));
  94 +
  95 + frame = av_frame_alloc();
  96 + cvt_frame = av_frame_alloc();
  97 +
  98 + // Get fps, stream time_base and allocate space for frame buffer with av_malloc.
  99 + fps = (float)avFormatCtx->streams[streamID]->avg_frame_rate.num /
  100 + (float)avFormatCtx->streams[streamID]->avg_frame_rate.den;
  101 + time_base = (float)avFormatCtx->streams[streamID]->time_base.num /
  102 + (float)avFormatCtx->streams[streamID]->time_base.den;
  103 + int framebytes = avpicture_get_size(AV_PIX_FMT_BGR24, avCodecCtx->width, avCodecCtx->height);
  104 + buffer = (uint8_t*)av_malloc(framebytes*sizeof(uint8_t));
  105 + avpicture_fill((AVPicture*)cvt_frame, buffer, AV_PIX_FMT_BGR24, avCodecCtx->width, avCodecCtx->height);
  106 +
  107 + avSwsCtx = sws_getContext(avCodecCtx->width, avCodecCtx->height,
  108 + avCodecCtx->pix_fmt,
  109 + avCodecCtx->width, avCodecCtx->height,
  110 + AV_PIX_FMT_BGR24,
  111 + SWS_BICUBIC,
  112 + NULL, NULL, NULL);
  113 +
  114 + // attempt to seek to first keyframe
  115 + if (av_seek_frame(avFormatCtx, streamID, avFormatCtx->streams[streamID]->start_time, 0) < 0)
  116 + qFatal("Could not seek to beginning keyframe for %s!", qPrintable(file.name));
  117 + avcodec_flush_buffers(avCodecCtx);
  118 +
  119 + opened = true;
  120 + }
  121 +
  122 + TemplateList readBlock(bool *done)
  123 + {
  124 + if (!opened) {
  125 + deferredInit();
  126 + }
  127 +
  128 + Template output;
  129 + output.file = file;
  130 +
  131 + AVPacket packet;
  132 + av_init_packet(&packet);
  133 + int ret = 0;
  134 + while (!ret) {
  135 + if (av_read_frame(avFormatCtx, &packet) >= 0) {
  136 + if (packet.stream_index == streamID) {
  137 + avcodec_decode_video2(avCodecCtx, frame, &ret, &packet);
  138 + idx = packet.dts; // decompression timestamp
  139 + av_free_packet(&packet);
  140 + } else {
  141 + av_free_packet(&packet);
  142 + }
  143 + } else {
  144 + av_free_packet(&packet);
  145 + release();
  146 + *done = true;
  147 + return TemplateList();
  148 + }
  149 + }
  150 +
  151 + // Convert from native format
  152 + sws_scale(avSwsCtx,
  153 + frame->data,
  154 + frame->linesize,
  155 + 0, avCodecCtx->height,
  156 + cvt_frame->data,
  157 + cvt_frame->linesize);
  158 +
  159 + // Write AVFrame to cv::Mat
  160 + output.m() = Mat(avCodecCtx->height, avCodecCtx->width, CV_8UC3, cvt_frame->data[0]).clone();
  161 + if (output.m().data) {
  162 + if (av_seek_frame(avFormatCtx, streamID, idx+1, 0) < 0)
  163 + *done = true;
  164 + avcodec_flush_buffers(avCodecCtx);
  165 +
  166 + QString URL = file.get<QString>("URL", file.name);
  167 + output.file.set("URL", URL + "#t=" + QString::number((int)(idx * time_base)) + "s");
  168 + output.file.set("frame", QString::number(idx * time_base * fps));
  169 + TemplateList dst;
  170 + dst.append(output);
  171 + return dst;
  172 + }
  173 + *done = true;
  174 + return TemplateList();
  175 + }
  176 +
  177 + void release()
  178 + {
  179 + if (avSwsCtx) sws_freeContext(avSwsCtx);
  180 + if (frame) av_free(frame);
  181 + if (cvt_frame) av_free(cvt_frame);
  182 + if (avCodecCtx) avcodec_close(avCodecCtx);
  183 + if (avFormatCtx) avformat_close_input(&avFormatCtx);
  184 + if (buffer) av_free(buffer);
  185 + avFormatCtx = NULL;
  186 + avCodecCtx = NULL;
  187 + avSwsCtx = NULL;
  188 + avCodec = NULL;
  189 + frame = NULL;
  190 + cvt_frame = NULL;
  191 + buffer = NULL;
  192 + }
  193 +
  194 + void write(const Template &t)
  195 + {
  196 + (void)t; qFatal("Not implemented");
  197 + }
  198 +
  199 +protected:
  200 + AVFormatContext *avFormatCtx;
  201 + AVCodecContext *avCodecCtx;
  202 + SwsContext *avSwsCtx;
  203 + AVCodec *avCodec;
  204 + AVFrame *frame;
  205 + AVFrame *cvt_frame;
  206 + uint8_t *buffer;
  207 + bool opened;
  208 + int streamID;
  209 + float fps;
  210 + float time_base;
  211 +};
  212 +
  213 +BR_REGISTER(Gallery,keyframesGallery)
  214 +
  215 +/*!
  216 + * \ingroup galleries
  217 + * \brief Read key frames of a .mp4 video file with LibAV
  218 + * \author Ben Klein \cite bhklein
  219 + */
  220 +class mp4Gallery : public keyframesGallery
  221 +{
  222 + Q_OBJECT
  223 +};
  224 +
  225 +BR_REGISTER(Gallery, mp4Gallery)
  226 +
  227 +} // namespace br
  228 +
  229 +#include "gallery/keyframes.moc"
share/openbr/cmake/FindLibAV.cmake 0 → 100644
  1 +# Module for locating libav.
  2 +#
  3 +# Customizable variables:
  4 +# LIBAV_ROOT_DIR
  5 +# Specifies libav's root directory.
  6 +#
  7 +# Read-only variables:
  8 +# LIBAV_FOUND
  9 +# Indicates whether the library has been found.
  10 +#
  11 +# LIBAV_INCLUDE_DIRS
  12 +# Specifies libav's include directory.
  13 +#
  14 +# LIBAV_LIBRARIES
  15 +# Specifies libav libraries that should be passed to target_link_libararies.
  16 +#
  17 +# LIBAV_<COMPONENT>_LIBRARIES
  18 +# Specifies the libraries of a specific <COMPONENT>.
  19 +#
  20 +# LIBAV_<COMPONENT>_FOUND
  21 +# Indicates whether the specified <COMPONENT> was found.
  22 +#
  23 +#
  24 +# Copyright (c) 2012 Sergiu Dotenco
  25 +#
  26 +# Permission is hereby granted, free of charge, to any person obtaining a copy
  27 +# of this software and associated documentation files (the "Software"), to deal
  28 +# in the Software without restriction, including without limitation the rights
  29 +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  30 +# copies of the Software, and to permit persons to whom the Software is
  31 +# furnished to do so, subject to the following conditions:
  32 +#
  33 +# The above copyright notice and this permission notice shall be included in all
  34 +# copies or substantial portions of the Software.
  35 +#
  36 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  37 +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  38 +# FITNESS FOR A PARTLIBAVLAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  39 +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  40 +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  41 +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  42 +# SOFTWARE.
  43 +
  44 +INCLUDE (FindPackageHandleStandardArgs)
  45 +
  46 +IF (CMAKE_VERSION VERSION_GREATER 2.8.7)
  47 + SET (_LIBAV_CHECK_COMPONENTS FALSE)
  48 +ELSE (CMAKE_VERSION VERSION_GREATER 2.8.7)
  49 + SET (_LIBAV_CHECK_COMPONENTS TRUE)
  50 +ENDIF (CMAKE_VERSION VERSION_GREATER 2.8.7)
  51 +
  52 +FIND_PATH (LIBAV_ROOT_DIR
  53 + NAMES include/libavcodec/avcodec.h
  54 + include/libavdevice/avdevice.h
  55 + include/libavfilter/avfilter.h
  56 + include/libavutil/avutil.h
  57 + include/libswscale/swscale.h
  58 + PATHS ENV LIBAVROOT
  59 + DOC "libav root directory")
  60 +
  61 +FIND_PATH (LIBAV_INCLUDE_DIR
  62 + NAMES libavcodec/avcodec.h
  63 + libavdevice/avdevice.h
  64 + libavfilter/avfilter.h
  65 + libavutil/avutil.h
  66 + libswscale/swscale.h
  67 + HINTS ${LIBAV_ROOT_DIR}
  68 + PATH_SUFFIXES include
  69 + DOC "libav include directory")
  70 +
  71 +if (NOT LibAV_FIND_COMPONENTS)
  72 + set (LibAV_FIND_COMPONENTS avcodec avdevice avfilter avformat avutil swscale)
  73 +endif (NOT LibAV_FIND_COMPONENTS)
  74 +
  75 +FOREACH (_LIBAV_COMPONENT ${LibAV_FIND_COMPONENTS})
  76 + STRING (TOUPPER ${_LIBAV_COMPONENT} _LIBAV_COMPONENT_UPPER)
  77 + SET (_LIBAV_LIBRARY_BASE LIBAV_${_LIBAV_COMPONENT_UPPER}_LIBRARY)
  78 +
  79 + FIND_LIBRARY (${_LIBAV_LIBRARY_BASE}
  80 + NAMES ${_LIBAV_COMPONENT}
  81 + HINTS ${LIBAV_ROOT_DIR}
  82 + PATH_SUFFIXES bin lib
  83 + DOC "libav ${_LIBAV_COMPONENT} library")
  84 +
  85 + MARK_AS_ADVANCED (${_LIBAV_LIBRARY_BASE})
  86 +
  87 + SET (LIBAV_${_LIBAV_COMPONENT_UPPER}_FOUND TRUE)
  88 + SET (LibAV_${_LIBAV_COMPONENT}_FOUND ${LIBAV_${_LIBAV_COMPONENT_UPPER}_FOUND})
  89 +
  90 + IF (${_LIBAV_LIBRARY_BASE})
  91 + # setup the LIBAV_<COMPONENT>_LIBRARIES variable
  92 + SET (LIBAV_${_LIBAV_COMPONENT_UPPER}_LIBRARIES ${${_LIBAV_LIBRARY_BASE}})
  93 + LIST (APPEND LIBAV_LIBRARIES ${LIBAV_${_LIBAV_COMPONENT_UPPER}_LIBRARIES})
  94 + LIST (APPEND _LIBAV_ALL_LIBS ${${_LIBAV_LIBRARY_BASE}})
  95 + ELSE (${_LIBAV_LIBRARY_BASE})
  96 + LIST (APPEND _LIBAV_MISSING_LIBRARIES ${_LIBAV_LIBRARY_BASE})
  97 + ENDIF (${_LIBAV_LIBRARY_BASE})
  98 +ENDFOREACH (_LIBAV_COMPONENT ${LibAV_FIND_COMPONENTS})
  99 +
  100 +SET (LIBAV_INCLUDE_DIRS ${LIBAV_INCLUDE_DIR})
  101 +
  102 +IF (DEFINED _LIBAV_MISSING_COMPONENTS AND _LIBAV_CHECK_COMPONENTS)
  103 + IF (NOT LibAV_FIND_QUIETLY)
  104 + MESSAGE (STATUS "One or more libav components were not found:")
  105 + # Display missing components indented, each on a separate line
  106 + FOREACH (_LIBAV_MISSING_COMPONENT ${_LIBAV_MISSING_COMPONENTS})
  107 + MESSAGE (STATUS " " ${_LIBAV_MISSING_COMPONENT})
  108 + ENDFOREACH (_LIBAV_MISSING_COMPONENT ${_LIBAV_MISSING_COMPONENTS})
  109 + ENDIF (NOT LibAV_FIND_QUIETLY)
  110 +ENDIF (DEFINED _LIBAV_MISSING_COMPONENTS AND _LIBAV_CHECK_COMPONENTS)
  111 +
  112 +# Determine library's version
  113 +
  114 +FIND_PROGRAM (LIBAV_AVCONV_EXECUTABLE NAMES avconv
  115 + HINTS ${LIBAV_ROOT_DIR}
  116 + PATH_SUFFIXES bin
  117 + DOC "avconv executable")
  118 +
  119 +IF (LIBAV_AVCONV_EXECUTABLE)
  120 + EXECUTE_PROCESS (COMMAND ${LIBAV_AVCONV_EXECUTABLE} -version
  121 + OUTPUT_VARIABLE _LIBAV_AVCONV_OUTPUT ERROR_QUIET)
  122 +
  123 + STRING (REGEX REPLACE ".*avconv[ \t]+([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1"
  124 + LIBAV_VERSION "${_LIBAV_AVCONV_OUTPUT}")
  125 + STRING (REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1"
  126 + LIBAV_VERSION_MAJOR "${LIBAV_VERSION}")
  127 + STRING (REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\2"
  128 + LIBAV_VERSION_MINOR "${LIBAV_VERSION}")
  129 + STRING (REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\3"
  130 + LIBAV_VERSION_PATCH "${LIBAV_VERSION}")
  131 +
  132 + SET (LIBAV_VERSION_COMPONENTS 3)
  133 +ENDIF (LIBAV_AVCONV_EXECUTABLE)
  134 +
  135 +IF (WIN32)
  136 + FIND_PROGRAM (LIB_EXECUTABLE NAMES lib
  137 + HINTS "$ENV{VS110COMNTOOLS}/../../VC/bin"
  138 + "$ENV{VS100COMNTOOLS}/../../VC/bin"
  139 + "$ENV{VS90COMNTOOLS}/../../VC/bin"
  140 + "$ENV{VS71COMNTOOLS}/../../VC/bin"
  141 + "$ENV{VS80COMNTOOLS}/../../VC/bin"
  142 + DOC "Library manager")
  143 +
  144 + MARK_AS_ADVANCED (LIB_EXECUTABLE)
  145 +ENDIF (WIN32)
  146 +
  147 +MACRO (GET_LIB_REQUISITES LIB REQUISITES)
  148 + IF (LIB_EXECUTABLE)
  149 + GET_FILENAME_COMPONENT (_LIB_PATH ${LIB_EXECUTABLE} PATH)
  150 +
  151 + EXECUTE_PROCESS (COMMAND ${LIB_EXECUTABLE} /nologo /list ${LIB}
  152 + WORKING_DIRECTORY ${_LIB_PATH}/../../Common7/IDE
  153 + OUTPUT_VARIABLE _LIB_OUTPUT ERROR_QUIET)
  154 +
  155 + STRING (REPLACE "\n" ";" "${REQUISITES}" "${_LIB_OUTPUT}")
  156 + LIST (REMOVE_DUPLICATES ${REQUISITES})
  157 + ENDIF (LIB_EXECUTABLE)
  158 +ENDMACRO (GET_LIB_REQUISITES)
  159 +
  160 +IF (_LIBAV_ALL_LIBS)
  161 + # collect lib requisites using the lib tool
  162 + FOREACH (_LIBAV_COMPONENT ${_LIBAV_ALL_LIBS})
  163 + GET_LIB_REQUISITES (${_LIBAV_COMPONENT} _LIBAV_REQUISITES)
  164 + ENDFOREACH (_LIBAV_COMPONENT)
  165 +ENDIF (_LIBAV_ALL_LIBS)
  166 +
  167 +IF (NOT LIBAV_BINARY_DIR)
  168 + SET (_LIBAV_UPDATE_BINARY_DIR TRUE)
  169 +ELSE (NOT LIBAV_BINARY_DIR)
  170 + SET (_LIBAV_UPDATE_BINARY_DIR FALSE)
  171 +ENDIF (NOT LIBAV_BINARY_DIR)
  172 +
  173 +SET (_LIBAV_BINARY_DIR_HINTS bin)
  174 +
  175 +IF (_LIBAV_REQUISITES)
  176 + FIND_FILE (LIBAV_BINARY_DIR NAMES ${_LIBAV_REQUISITES}
  177 + HINTS ${LIBAV_ROOT_DIR}
  178 + PATH_SUFFIXES ${_LIBAV_BINARY_DIR_HINTS} NO_DEFAULT_PATH)
  179 +ENDIF (_LIBAV_REQUISITES)
  180 +
  181 +IF (LIBAV_BINARY_DIR AND _LIBAV_UPDATE_BINARY_DIR)
  182 + SET (_LIBAV_BINARY_DIR ${LIBAV_BINARY_DIR})
  183 + UNSET (LIBAV_BINARY_DIR CACHE)
  184 +
  185 + IF (_LIBAV_BINARY_DIR)
  186 + GET_FILENAME_COMPONENT (LIBAV_BINARY_DIR ${_LIBAV_BINARY_DIR} PATH)
  187 + ENDIF (_LIBAV_BINARY_DIR)
  188 +ENDIF (LIBAV_BINARY_DIR AND _LIBAV_UPDATE_BINARY_DIR)
  189 +
  190 +SET (LIBAV_BINARY_DIR ${LIBAV_BINARY_DIR} CACHE PATH "libav binary directory")
  191 +
  192 +MARK_AS_ADVANCED (LIBAV_INCLUDE_DIR LIBAV_BINARY_DIR)
  193 +
  194 +IF (NOT _LIBAV_CHECK_COMPONENTS)
  195 + SET (_LIBAV_FPHSA_ADDITIONAL_ARGS HANDLE_COMPONENTS)
  196 +ENDIF (NOT _LIBAV_CHECK_COMPONENTS)
  197 +
  198 +FIND_PACKAGE_HANDLE_STANDARD_ARGS (LibAV REQUIRED_VARS LIBAV_ROOT_DIR
  199 + LIBAV_INCLUDE_DIR ${_LIBAV_MISSING_LIBRARIES} VERSION_VAR LIBAV_VERSION
  200 + ${_LIBAV_FPHSA_ADDITIONAL_ARGS})
0 \ No newline at end of file 201 \ No newline at end of file