Skip to content

Instantly share code, notes, and snippets.

Created March 21, 2014 23:18
Show Gist options
  • Save anonymous/9698508 to your computer and use it in GitHub Desktop.
Save anonymous/9698508 to your computer and use it in GitHub Desktop.
motion_watch.c
/*
* Copyright (c) 2010 Nicolas George
* Copyright (c) 2011 Stefano Sabatini
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @file
* API example for decoding and filtering
* @example doc/examples/filtering_video.c
*/
#define _XOPEN_SOURCE 600 /* for usleep */
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avcodec.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <limits.h>
#include <string.h>
#define MAX_EVENTS 1024 /*Max. number of events to process at one go*/
#define LEN_NAME 16 /*Assuming that the length of the filename won't exceed 16 bytes*/
#define EVENT_SIZE ( sizeof (struct inotify_event) ) /*size of one event*/
#define BUF_LEN ( MAX_EVENTS * ( EVENT_SIZE + LEN_NAME )) /*buffer to store the data of events*/
#define IS_INTERLACED(a) ((a)&MB_TYPE_INTERLACED)
#define IS_16X16(a) ((a)&MB_TYPE_16x16)
#define IS_16X8(a) ((a)&MB_TYPE_16x8)
#define IS_8X16(a) ((a)&MB_TYPE_8x16)
#define IS_8X8(a) ((a)&MB_TYPE_8x8)
#define USES_LIST(a, list) ((a) & ((MB_TYPE_P0L0|MB_TYPE_P1L0)<<(2*(list))))
//FFMpeg interface change
#define FF_I_TYPE AV_PICTURE_TYPE_I ///< Intra
#define FF_P_TYPE AV_PICTURE_TYPE_P ///< Predicted
#define FF_B_TYPE AV_PICTURE_TYPE_B ///< Bi-dir predicted
#define FF_S_TYPE AV_PICTURE_TYPE_S ///< S(GMC)-VOP MPEG4
#define FF_SI_TYPE AV_PICTURE_TYPE_SI ///< Switching Intra
#define FF_SP_TYPE AV_PICTURE_TYPE_SP ///< Switching Predicted
#define FF_BI_TYPE AV_PICTURE_TYPE_BI
#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO
int count = 0;
double sum = 0;
double h;
double w;
double cutoff;
static AVFormatContext *fmt_ctx;
static AVCodecContext *dec_ctx;
AVFilterContext *buffersink_ctx;
AVFilterContext *buffersrc_ctx;
static int video_stream_index = -1;
static int64_t last_pts = AV_NOPTS_VALUE;
static int open_input_file(const char *filename)
{
int ret;
AVCodec *dec;
if ((ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL)) < 0) {
av_log(NULL, AV_LOG_INFO, "Cannot open input file\n");
return ret;
}
if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) {
av_log(NULL, AV_LOG_INFO, "Cannot find stream information\n");
return ret;
}
/* select the video stream */
ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &dec, 0);
if (ret < 0) {
av_log(NULL, AV_LOG_INFO, "Cannot find a video stream in the input file\n");
return ret;
}
video_stream_index = ret;
dec_ctx = fmt_ctx->streams[video_stream_index]->codec;
/* init the video decoder */
if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) {
av_log(NULL, AV_LOG_INFO, "Cannot open video decoder\n");
return ret;
}
return 0;
}
void print_vector(int x, int y, int dx, int dy)
{
if (dx != 10000 && dy != 10000){
//sum = sum + sqrt((double)dx*(double)dx/w/w + (double)dy*(double)dy/h/h);
sum = sum + sqrt(dx*dx+dy*dy);
count++;
}
//if ((dx > 5 || dy > 5) && (dx != 10000 && dy != 10000)) {
//printf("%d %d ; %d %d\n", x, y, dx, dy);
//}
}
/* Print motion vector for each macroblock in this frame. If there is
* no motion vector in some macroblock, it prints a magic number NO_MV. */
void printMVMatrix(int index, AVFrame *pict, AVCodecContext *ctx)
{
const int mb_width = (ctx->width + 15) / 16;
const int mb_height = (ctx->height + 15) / 16;
const int mb_stride = mb_width + 1;
const int mv_sample_log2 = 4 - pict->motion_subsample_log2;
const int mv_stride = (mb_width << mv_sample_log2) + (ctx->codec_id == CODEC_ID_H264 ? 0 : 1);
const int quarter_sample = (ctx->flags & CODEC_FLAG_QPEL) != 0;
const int shift = 1 + quarter_sample;
//printf("frame %d, %d x %d\n", index, mb_height, mb_width);
for (int mb_y = 0; mb_y < mb_height; mb_y++) {
for (int mb_x = 0; mb_x < mb_width; mb_x++) {
const int mb_index = mb_x + mb_y * mb_stride;
if (pict->motion_val) {
for (int type = 0; type < 3; type++) {
int direction = 0;
switch (type) {
case 0:
if (pict->pict_type != FF_P_TYPE)
continue;
direction = 0;
break;
case 1:
if (pict->pict_type != FF_B_TYPE)
continue;
direction = 0;
break;
case 2:
if (pict->pict_type != FF_B_TYPE)
continue;
direction = 1;
break;
}
if (!USES_LIST(pict->mb_type[mb_index], direction)) {
#define NO_MV 10000
if (IS_8X8(pict->mb_type[mb_index])) {
print_vector(mb_x, mb_y, NO_MV, NO_MV);
print_vector(mb_x, mb_y, NO_MV, NO_MV);
print_vector(mb_x, mb_y, NO_MV, NO_MV);
print_vector(mb_x, mb_y, NO_MV, NO_MV);
} else if (IS_16X8(pict->mb_type[mb_index])) {
print_vector(mb_x, mb_y, NO_MV, NO_MV);
print_vector(mb_x, mb_y, NO_MV, NO_MV);
} else if (IS_8X16(pict->mb_type[mb_index])) {
print_vector(mb_x, mb_y, NO_MV, NO_MV);
print_vector(mb_x, mb_y, NO_MV, NO_MV);
} else {
print_vector(mb_x, mb_y, NO_MV, NO_MV);
}
#undef NO_MV
continue;
}
if (IS_8X8(pict->mb_type[mb_index])) {
for (int i = 0; i < 4; i++) {
int xy = (mb_x*2 + (i&1) + (mb_y*2 + (i>>1))*mv_stride) << (mv_sample_log2-1);
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
print_vector(mb_x, mb_y, dx, dy);
}
} else if (IS_16X8(pict->mb_type[mb_index])) {
for (int i = 0; i < 2; i++) {
int xy = (mb_x*2 + (mb_y*2 + i)*mv_stride) << (mv_sample_log2-1);
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
if (IS_INTERLACED(pict->mb_type[mb_index]))
dy *= 2;
print_vector(mb_x, mb_y, dx, dy);
}
} else if (IS_8X16(pict->mb_type[mb_index])) {
for (int i = 0; i < 2; i++) {
int xy = (mb_x*2 + i + mb_y*2*mv_stride) << (mv_sample_log2-1);
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
if (IS_INTERLACED(pict->mb_type[mb_index]))
dy *= 2;
print_vector(mb_x, mb_y, dx, dy);
}
} else {
int xy = (mb_x + mb_y*mv_stride) << mv_sample_log2;
int dx = (pict->motion_val[direction][xy][0]>>shift);
int dy = (pict->motion_val[direction][xy][1]>>shift);
print_vector(mb_x, mb_y, dx, dy);
}
}
}
//printf("--\n");
}
//printf("====\n");
}
}
void motion_watch( char *input_f )
{
int ret;
count = 0;
sum = 0;
AVPacket packet;
AVFrame *frame = avcodec_alloc_frame();
int got_frame;
if (!frame) {
perror("Could not allocate frame");
}
avcodec_register_all();
av_register_all();
if ((ret = open_input_file(input_f)) < 0)
goto end;
dec_ctx->skip_loop_filter = AVDISCARD_ALL; //1m12s -> 54s
//dec_ctx->skip_idct = AVDISCARD_ALL; //did nothing - think h.264 doesn't touch these
//dec_ctx->idct_algo = FF_IDCT_SIMPLEARMV6; // did nothing
//dec_ctx->idct_algo = FF_IDCT_SIMPLENEON; // did nothing
//dec_ctx->idct_algo = FF_IDCT_INT; // did nothing
//dec_ctx->lowres=2; //spewed errors and crashed
//dec_ctx->bits_per_coded_sample=2; //did nothing
//dec_ctx->draw_horiz_band =(int)1; // cored
//dec_ctx->skip_frame = AVDISCARD_ALL; // did nothing - 55->47 and sprewed loads of errors
//dec_ctx->skip_top=(int)128; // did nothing
//dec_ctx->thread_count=2; // didn't do anything
//dec_ctx->flags2 |= CODEC_FLAG2_FAST; // didn't do anthing
dec_ctx->flags |= CODEC_FLAG_GRAY; // 55s->46s
//dec_ctx->flags |= CODEC_FLAG_LOOP_FILTER; // didnt do anything
//dec_ctx->flags2 |= CODEC_FLAG2_IGNORE_CROP; // didn't do anything
/* read all packets */
int f = 1;
time_t start_t, end_t;
double diff_t;
time(&start_t);
while (1) {
AVFilterBufferRef *picref;
if ((ret = av_read_frame(fmt_ctx, &packet)) < 0)
break;
//if (packet.stream_index == video_stream_index) {
if (packet.stream_index == video_stream_index && ( f % 6 == 0 || (f-1) % 6==0 || f<10 )) { // process only every seond packet 46->25 (every 3rd -> 17s
avcodec_get_frame_defaults(frame);
got_frame = 0;
ret = avcodec_decode_video2(dec_ctx, frame, &got_frame, &packet);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Error decoding video\n");
break;
}
if (got_frame) {
if(frame->pict_type != FF_I_TYPE) {
//printf("Got frame \n");
printMVMatrix( f, frame, dec_ctx );
}
}
}
++f;
av_free_packet(&packet);
}
end:
time(&end_t);
diff_t = difftime(end_t, start_t);
printf("Execution time = %f\n", diff_t);
printf("[%d] sum mv: %f, total # mv: %d\n",start_t,sum,count);
if (dec_ctx)
avcodec_close(dec_ctx);
if (fmt_ctx)
avformat_close_input(&fmt_ctx);
if (frame)
av_freep(&frame);
}
int main( int argc, char **argv )
{
int length, i = 0, wd;
int fd;
char buffer[BUF_LEN];
/* Initialize Inotify*/
fd = inotify_init();
if ( fd < 0 ) {
perror( "Couldn't initialize inotify");
}
/* add watch to starting directory */
wd = inotify_add_watch(fd, argv[1], IN_CLOSE_WRITE );
if (wd == -1)
{
printf("Couldn't add watch to %s\n",argv[1]);
}
else
{
printf("Watching:: %s\n",argv[1]);
}
/* do it forever*/
while(1)
{
i = 0;
length = read( fd, buffer, BUF_LEN );
if ( length < 0 ) {
perror( "read" );
}
while ( i < length ) {
struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
if ( event->len ) {
if ( event->mask & IN_CLOSE_WRITE) {
if ( ! (event->mask & IN_ISDIR)) {
char *dot = strrchr(event->name, '.');
if (dot && !strcmp(dot, ".ts")) {
char fname[200];
strcpy(fname, argv[1]);
strcat(fname, event->name);
printf( "New video segment %s\n", fname );
motion_watch(fname);
}
}
}
i += EVENT_SIZE + event->len;
}
}
}
/* Clean up*/
inotify_rm_watch( fd, wd );
close( fd );
return 0;
}
@jhallard
Copy link

Are you sure that your frame-skipping works correctly? If you don't decode one frame don't you lose information about all subsequent frames until another Iframe appears?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment