Packages

Bindings to the C++ pHash library (phash.org).

Current section

Files

Jump to
phash c_lib pHash src cimgffmpeg.cpp
Raw

c_lib/pHash/src/cimgffmpeg.cpp

/*
pHash, the open source perceptual hash library
Copyright (C) 2009 Aetilius, Inc.
All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Evan Klinger - eklinger@phash.org
D Grant Starkweather - dstarkweather@phash.org
*/
#include "cimgffmpeg.h"
void vfinfo_close(VFInfo *vfinfo) {
if (vfinfo->pFormatCtx != NULL) {
avcodec_close(vfinfo->pCodecCtx);
vfinfo->pCodecCtx = NULL;
avformat_close_input(&vfinfo->pFormatCtx);
vfinfo->pFormatCtx = NULL;
vfinfo->width = -1;
vfinfo->height = -1;
}
}
int ReadFrames(VFInfo *st_info, CImgList<uint8_t> *pFrameList,
unsigned int low_index, unsigned int hi_index) {
// target pixel format
AVPixelFormat ffmpeg_pixfmt;
if (st_info->pixelformat == 0)
ffmpeg_pixfmt = AV_PIX_FMT_GRAY8;
else
ffmpeg_pixfmt = AV_PIX_FMT_RGB24;
st_info->next_index = low_index;
if (st_info->pFormatCtx == NULL) {
st_info->current_index = 0;
av_log_set_level(AV_LOG_QUIET);
// Open video file
if (avformat_open_input(&st_info->pFormatCtx, st_info->filename, NULL,
NULL) != 0)
return -1; // Couldn't open file
// Retrieve stream information
if (avformat_find_stream_info(st_info->pFormatCtx, NULL) < 0)
return -1; // Couldn't find stream information
// dump_format(pFormatCtx,0,NULL,0);//debugging function to print
// infomation about format
unsigned int i;
// Find the video stream
for (i = 0; i < st_info->pFormatCtx->nb_streams; i++) {
if (st_info->pFormatCtx->streams[i]->codec->codec_type ==
AVMEDIA_TYPE_VIDEO) {
st_info->videoStream = i;
break;
}
}
if (st_info->videoStream == -1) return -1; // no video stream
// Get a pointer to the codec context for the video stream
st_info->pCodecCtx =
st_info->pFormatCtx->streams[st_info->videoStream]->codec;
if (st_info->pCodecCtx == NULL) {
return -1;
}
// Find the decoder
st_info->pCodec = avcodec_find_decoder(st_info->pCodecCtx->codec_id);
if (st_info->pCodec == NULL) {
return -1; // Codec not found
}
// Open codec
if (avcodec_open2(st_info->pCodecCtx, st_info->pCodec, NULL) < 0)
return -1; // Could not open codec
st_info->height = (st_info->height <= 0) ? st_info->pCodecCtx->height
: st_info->height;
st_info->width =
(st_info->width <= 0) ? st_info->pCodecCtx->width : st_info->width;
}
AVFrame *pFrame;
// Allocate video frame
pFrame = av_frame_alloc();
if (pFrame == NULL) return -1;
// Allocate an AVFrame structure
AVFrame *pConvertedFrame = av_frame_alloc();
if (pConvertedFrame == NULL) return -1;
uint8_t *buffer;
int numBytes;
// Determine required buffer size and allocate buffer
numBytes =
avpicture_get_size(ffmpeg_pixfmt, st_info->width, st_info->height);
buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
if (buffer == NULL) return -1;
avpicture_fill((AVPicture *)pConvertedFrame, buffer, ffmpeg_pixfmt,
st_info->width, st_info->height);
int frameFinished;
int size = 0;
int channels = ffmpeg_pixfmt == AV_PIX_FMT_GRAY8 ? 1 : 3;
AVPacket packet;
int result = 1;
CImg<uint8_t> next_image;
SwsContext *c = sws_getContext(
st_info->pCodecCtx->width, st_info->pCodecCtx->height,
st_info->pCodecCtx->pix_fmt, st_info->width, st_info->height,
ffmpeg_pixfmt, SWS_BICUBIC, NULL, NULL, NULL);
while ((result >= 0) && (size < st_info->nb_retrieval) &&
(st_info->current_index <= hi_index)) {
result = av_read_frame(st_info->pFormatCtx, &packet);
if (result < 0) break;
if (packet.stream_index == st_info->videoStream) {
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = packet.data;
avpkt.size = packet.size;
//
// HACK for CorePNG to decode as normal PNG by default
// same method used by ffmpeg
avpkt.flags = AV_PKT_FLAG_KEY;
avcodec_decode_video2(st_info->pCodecCtx, pFrame, &frameFinished,
&avpkt);
// avcodec_decode_video(st_info->pCodecCtx, pFrame,
// &frameFinished,packet.data, packet.size);
if (frameFinished) {
if (st_info->current_index == st_info->next_index) {
st_info->next_index += st_info->step;
sws_scale(c, pFrame->data, pFrame->linesize, 0,
st_info->pCodecCtx->height, pConvertedFrame->data,
pConvertedFrame->linesize);
next_image.assign(*pConvertedFrame->data, channels,
st_info->width, st_info->height, 1, true);
next_image.permute_axes("yzcx");
pFrameList->push_back(next_image);
size++;
}
st_info->current_index++;
}
av_free_packet(&packet);
}
}
if (result < 0) {
avcodec_close(st_info->pCodecCtx);
avformat_close_input(&st_info->pFormatCtx);
st_info->pFormatCtx = NULL;
st_info->pCodecCtx = NULL;
st_info->width = -1;
st_info->height = -1;
}
av_free(buffer);
buffer = NULL;
av_free(pConvertedFrame);
pConvertedFrame = NULL;
av_free(pFrame);
pFrame = NULL;
sws_freeContext(c);
c = NULL;
return size;
}
int NextFrames(VFInfo *st_info, CImgList<uint8_t> *pFrameList) {
AVPixelFormat ffmpeg_pixfmt;
if (st_info->pixelformat == 0) {
ffmpeg_pixfmt = AV_PIX_FMT_GRAY8;
} else {
ffmpeg_pixfmt = AV_PIX_FMT_RGB24;
}
if (st_info->pFormatCtx == NULL) {
st_info->current_index = 0;
st_info->next_index = 0;
st_info->videoStream = -1;
// st_info->pFormatCtx =
// (AVFormatContext*)malloc(sizeof(AVFormatContext)); st_info->pCodecCtx
// = (AVCodecContext*)malloc(sizeof(AVCodecContext)); st_info->pCodec =
// (AVCodec*)malloc(sizeof(AVCodec));
av_log_set_level(AV_LOG_QUIET);
// Open video file
if (avformat_open_input(&st_info->pFormatCtx, st_info->filename, NULL,
NULL) != 0) {
return -1; // Couldn't open file
}
// Retrieve stream information
if (avformat_find_stream_info(st_info->pFormatCtx, NULL) < 0) {
return -1; // Couldn't find stream information
}
unsigned int i;
// Find the video stream
for (i = 0; i < st_info->pFormatCtx->nb_streams; i++) {
if (st_info->pFormatCtx->streams[i]->codec->codec_type ==
AVMEDIA_TYPE_VIDEO) {
st_info->videoStream = i;
break;
}
}
if (st_info->videoStream == -1) {
return -1; // no video stream
}
// Get a pointer to the codec context for the video stream
st_info->pCodecCtx =
st_info->pFormatCtx->streams[st_info->videoStream]->codec;
// Find the decoder
st_info->pCodec = avcodec_find_decoder(st_info->pCodecCtx->codec_id);
if (st_info->pCodec == NULL) {
return -1; // Codec not found
}
// Open codec
if (avcodec_open2(st_info->pCodecCtx, st_info->pCodec, NULL) < 0) {
return -1; // Could not open codec
}
st_info->width =
(st_info->width <= 0) ? st_info->pCodecCtx->width : st_info->width;
st_info->height = (st_info->height <= 0) ? st_info->pCodecCtx->height
: st_info->height;
}
AVFrame *pFrame;
// Allocate video frame
pFrame = av_frame_alloc();
// Allocate an AVFrame structure
AVFrame *pConvertedFrame = av_frame_alloc();
if (pConvertedFrame == NULL) {
return -1;
}
uint8_t *buffer;
int numBytes;
// Determine required buffer size and allocate buffer
numBytes =
avpicture_get_size(ffmpeg_pixfmt, st_info->width, st_info->height);
buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
if (buffer == NULL) {
return -1;
}
avpicture_fill((AVPicture *)pConvertedFrame, buffer, ffmpeg_pixfmt,
st_info->width, st_info->height);
int frameFinished;
int size = 0;
AVPacket packet;
int result = 1;
CImg<uint8_t> next_image;
SwsContext *c = sws_getContext(
st_info->pCodecCtx->width, st_info->pCodecCtx->height,
st_info->pCodecCtx->pix_fmt, st_info->width, st_info->height,
ffmpeg_pixfmt, SWS_BICUBIC, NULL, NULL, NULL);
while ((result >= 0) && (size < st_info->nb_retrieval)) {
result = av_read_frame(st_info->pFormatCtx, &packet);
if (result < 0) break;
if (packet.stream_index == st_info->videoStream) {
int channels = ffmpeg_pixfmt == AV_PIX_FMT_GRAY8 ? 1 : 3;
AVPacket avpkt;
av_init_packet(&avpkt);
avpkt.data = packet.data;
avpkt.size = packet.size;
//
// HACK for CorePNG to decode as normal PNG by default
// same method used by ffmpeg
avpkt.flags = AV_PKT_FLAG_KEY;
avcodec_decode_video2(st_info->pCodecCtx, pFrame, &frameFinished,
&avpkt);
// avcodec_decode_video(st_info->pCodecCtx, pFrame, &frameFinished,
// packet.data,packet.size);
if (frameFinished) {
if (st_info->current_index == st_info->next_index) {
st_info->next_index += st_info->step;
sws_scale(c, pFrame->data, pFrame->linesize, 0,
st_info->pCodecCtx->height, pConvertedFrame->data,
pConvertedFrame->linesize);
next_image.assign(*pConvertedFrame->data, channels,
st_info->width, st_info->height, 1, true);
next_image.permute_axes("yzcx");
pFrameList->push_back(next_image);
size++;
}
st_info->current_index++;
}
}
av_free_packet(&packet);
}
av_free(buffer);
buffer = NULL;
av_free(pConvertedFrame);
pConvertedFrame = NULL;
av_free(pFrame);
pFrame = NULL;
sws_freeContext(c);
c = NULL;
if (result < 0) {
avcodec_close(st_info->pCodecCtx);
avformat_close_input(&st_info->pFormatCtx);
st_info->pCodecCtx = NULL;
st_info->pFormatCtx = NULL;
st_info->pCodec = NULL;
st_info->width = -1;
st_info->height = -1;
}
return size;
}
int GetNumberStreams(const char *file) {
AVFormatContext *pFormatCtx;
av_log_set_level(AV_LOG_QUIET);
// Open video file
if (avformat_open_input(&pFormatCtx, file, NULL, NULL))
return -1; // Couldn't open file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1; // Couldn't find stream information
int result = pFormatCtx->nb_streams;
avformat_close_input(&pFormatCtx);
return result;
}
long GetNumberVideoFrames(const char *file) {
long nb_frames = -1;
AVFormatContext *pFormatCtx = avformat_alloc_context();
av_log_set_level(AV_LOG_QUIET);
// Open video file
if (avformat_open_input(&pFormatCtx, file, NULL, NULL)) {
// Couldn't open file
goto freeContext;
}
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
// Couldn't find stream information
goto closeContext;
}
// Find the first video stream
{
int videoStream = -1;
for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type ==
AVMEDIA_TYPE_VIDEO) {
videoStream = i;
break;
}
}
if (videoStream == -1) {
goto closeContext;
}
AVStream *str = pFormatCtx->streams[videoStream];
nb_frames = str->nb_frames;
if (nb_frames <= 0) {
nb_frames = (long)av_index_search_timestamp(
str, str->duration, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
}
if (nb_frames <= 0) {
int timebase = str->time_base.den / str->time_base.num;
nb_frames = str->duration / timebase;
}
}
closeContext:
avformat_close_input(&pFormatCtx);
freeContext:
avformat_free_context(pFormatCtx);
return nb_frames;
}
float fps(const char *filename) {
float result = 0;
AVFormatContext *pFormatCtx = avformat_alloc_context();
// Open video file
if (avformat_open_input(&pFormatCtx, filename, NULL, NULL)) {
avformat_free_context(pFormatCtx);
return -1; // Couldn't open file
}
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
avformat_close_input(&pFormatCtx);
avformat_free_context(pFormatCtx);
return -1; // Couldn't find stream information
}
// Find the first video stream
int videoStream = -1;
for (unsigned int i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
break;
}
}
if (videoStream == -1) return -1; // Didn't find a video stream
int num = (pFormatCtx->streams[videoStream]->r_frame_rate).num;
int den = (pFormatCtx->streams[videoStream]->r_frame_rate).den;
result = num / den;
avformat_close_input(&pFormatCtx);
avformat_free_context(pFormatCtx);
return result;
}