2
* Copyright (C) 2007 Johan MATHE - johan.mathe@tremplin-utc.net - Centre
3
* Pompfidou - IRI This library is free software; you can redistribute it
4
* and/or modify it under the terms of the GNU Lesser General Public
5
* License as published by the Free Software Foundation; either version
6
* 2.1 of the License, or (at your option) any later version. This
7
* library is distributed in the hope that it will be useful, but WITHOUT
8
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
9
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10
* License for more details. You should have received a copy of the GNU
11
* Lesser General Public License along with this library; if not, write to
12
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
13
* Boston, MA 02110-1301 USA $Id: film.cpp 141 2007-04-02 16:10:53Z
14
* johmathe $ $Date: 2009-09-18 18:27:54 +0100 (Fri, 18 Sep 2009) $
21
#include <ffmpeg/swscale.h>
26
film::do_stats (int frame_num)
31
film::create_main_dir ()
36
str << this->global_path;
37
buf = (struct stat *) malloc (sizeof (struct stat));
38
if (stat (str.str ().c_str (), buf) == -1)
41
mkdir (str.str ().c_str ());
43
mkdir (str.str ().c_str (), 0777);
51
film::CompareFrame (AVFrame * pFrame, AVFrame * pFramePrev)
57
int c1tot, c2tot, c3tot;
61
char c1prev, c2prev, c3prev;
64
for (y = 0; y < height; y++)
66
for (x = 0; x < width; x++)
69
c1 = (char) *(pFrame->data[0] + y * pFrame->linesize[0] + x * 3);
70
c2 = (char) *(pFrame->data[0] + y * pFrame->linesize[0] + x * 3 + 1);
71
c3 = (char) *(pFrame->data[0] + y * pFrame->linesize[0] + x * 3 + 2);
73
c1prev = (char) *(pFramePrev->data[0] + y * pFramePrev->linesize[0] + x * 3);
74
c2prev = (char) *(pFramePrev->data[0] + y * pFramePrev->linesize[0] + x * 3 + 1);
75
c3prev = (char) *(pFramePrev->data[0] + y * pFramePrev->linesize[0] + x * 3 + 2);
76
c1tot += int (c1 + 127);
77
c2tot += int (c2 + 127);
78
c3tot += int (c3 + 127);
79
score += abs ((c1 - c1prev));
80
score += abs ((c2 - c2prev));
81
score += abs ((c3 - c3prev));
84
int nbpx = (height * width);
87
* On se ramene à la moyenne
98
diff = abs (score - prev_score);
101
g->push_data (score, c1tot, c2tot, c3tot);
103
if (diff > this->threshold && score > this->threshold)
106
s.fbegin = frame_number;
107
s.msbegin = int ((frame_number * 1000) / fps);
108
s.myid = shots.back ().myid + 1;
111
cerr << "Shot log :: " << s.msbegin << endl;
117
shots.back ().fduration = frame_number - shots.back ().fbegin;
118
shots.back ().msduration = int (((shots.back ().fduration) * 1000) / fps);
121
* Create images if necessary
123
if (this->first_img_set)
125
image *im_begin = new image (this, width, height, s.myid, BEGIN);
126
im_begin->SaveFrame (pFrame);
127
s.img_begin = im_begin;
129
if (this->last_img_set)
131
image *im_end = new image (this, width, height, s.myid - 1, END);
132
im_end->SaveFrame (pFramePrev);
133
shots.back ().img_end = im_end;
140
film::update_metadata ()
144
if (videoStream != -1)
146
this->height = int (pFormatCtx->streams[videoStream]->codec->height);
147
this->width = int (pFormatCtx->streams[videoStream]->codec->width);
148
this->fps = av_q2d (pFormatCtx->streams[videoStream]->r_frame_rate);
149
avcodec_string (buf, sizeof (buf), pFormatCtx->streams[videoStream]->codec, 0);
150
this->codec.video = buf;
154
this->codec.video = "null";
161
if (audioStream != -1)
163
avcodec_string (buf, sizeof (buf), pCodecCtxAudio, 0);
164
this->codec.audio = buf;
165
this->nchannel = pCodecCtxAudio->channels;
166
this->samplerate = pCodecCtxAudio->sample_rate;
170
this->codec.audio = "null";
172
this->samplerate = 0;
175
duration.secs = pFormatCtx->duration / AV_TIME_BASE;
176
duration.us = pFormatCtx->duration % AV_TIME_BASE;
177
duration.mstotal = int (duration.secs * 1000 + duration.us / 1000);
178
duration.mins = duration.secs / 60;
180
duration.hours = duration.mins / 60;
186
film::shotlog (string message)
189
cerr << "Shot log :: " << message << endl;
202
static struct SwsContext *img_convert_ctx = NULL;
206
string graphpath = this->global_path + "/";
207
g = new graph (600, 400, graphpath, threshold, this);
208
g->set_title ("Motion quantity");
211
* Register all formats and codecs
215
if (av_open_input_file (&pFormatCtx, input_path.c_str (), NULL, 0, NULL) != 0)
217
string error_msg = "Impossible to open file";
218
error_msg += input_path;
220
return -1; // Couldn't open file
224
* Retrieve stream information
226
if (av_find_stream_info (pFormatCtx) < 0)
227
return -1; // Couldn't find stream information
230
// dump_format (pFormatCtx, 0, path.c_str (), false);
236
* Detect streams types
238
for (int j = 0; j < pFormatCtx->nb_streams; j++)
240
switch (pFormatCtx->streams[j]->codec->codec_type)
242
case CODEC_TYPE_VIDEO:
246
case CODEC_TYPE_AUDIO:
258
* Get a pointer to the codec context for the video stream
260
if (audioStream != -1)
264
string xml_audio = graphpath + "/" + "audio.xml";
265
init_xml (xml_audio);
268
pCodecCtxAudio = pFormatCtx->streams[audioStream]->codec;
269
pCodecAudio = avcodec_find_decoder (pCodecCtxAudio->codec_id);
271
if (pCodecAudio == NULL)
272
return -1; // Codec not found
273
if (avcodec_open (pCodecCtxAudio, pCodecAudio) < 0)
274
return -1; // Could not open codec
279
* Find the decoder for the video stream
281
if (videoStream != -1)
283
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
284
pCodec = avcodec_find_decoder (pCodecCtx->codec_id);
287
return -1; // Codec not found
288
if (avcodec_open (pCodecCtx, pCodec) < 0)
289
return -1; // Could not open codec
292
* Allocate video frame
294
pFrame = avcodec_alloc_frame ();
295
pFrameRGB = avcodec_alloc_frame ();
296
pFrameRGBprev = avcodec_alloc_frame ();
299
* Determine required buffer size and allocate buffer
301
numBytes = avpicture_get_size (PIX_FMT_RGB24, width, height);
303
buffer = (uint8_t *) malloc (sizeof (uint8_t) * numBytes);
304
buffer2 = (uint8_t *) malloc (sizeof (uint8_t) * numBytes);
307
* Assign appropriate parts of buffer to image planes in pFrameRGB
309
avpicture_fill ((AVPicture *) pFrameRGB, buffer, PIX_FMT_RGB24, width, height);
311
avpicture_fill ((AVPicture *) pFrameRGBprev, buffer2, PIX_FMT_RGB24, width, height);
315
* Mise en place du premier plan
327
checknumber = (samplerate * samplearg) / 1000;
330
* Boucle de traitement principale du flux
332
this->frame_number = 0;
333
while (av_read_frame (pFormatCtx, &packet) >= 0)
335
if (packet.stream_index == videoStream)
337
avcodec_decode_video (pCodecCtx, pFrame, &frameFinished, packet.data, packet.size);
341
// Convert the image into RGB24
342
if (! img_convert_ctx)
344
img_convert_ctx = sws_getContext(width, height, pCodecCtx->pix_fmt,
345
width, height, PIX_FMT_RGB24, SWS_BICUBIC,
347
if (! img_convert_ctx)
349
fprintf(stderr, "Cannot initialize the conversion context!\n");
354
/* API: int sws_scale(SwsContext *c, uint8_t *src, int srcStride[], int srcSliceY, int srcSliceH, uint8_t dst[], int dstStride[] )
356
sws_scale(img_convert_ctx, pFrame->data,
359
pFrameRGB->data, pFrameRGB->linesize);
362
Old API doc (cf http://www.dranger.com/ffmpeg/functions.html )
363
int img_convert(AVPicture *dst, int dst_pix_fmt,
364
const AVPicture *src, int src_pix_fmt,
365
int src_width, int src_height)
368
img_convert ((AVPicture *) pFrameRGB, PIX_FMT_RGB24, (AVPicture *) pFrame, pCodecCtx->pix_fmt, width, height);
371
this->frame_number ++;
372
/* Si ce n'est pas la permiere image */
373
if ( this->frame_number > 2)
375
CompareFrame (pFrameRGB, pFrameRGBprev);
380
* Cas ou c'est la premiere image, on cree la premiere image dans tous les cas
382
image *begin_i = new image (this, width, height, s.myid, BEGIN);
383
begin_i->create_img_dir ();
384
begin_i->SaveFrame (pFrameRGB);
385
shots.back ().img_begin = begin_i;
387
memcpy (buffer2, buffer, numBytes);
390
if (audio_set && (packet.stream_index == audioStream))
395
* Free the packet that was allocated by av_read_frame
397
if (packet.data != NULL)
398
av_free_packet (&packet);
401
if (videoStream != -1)
403
/* Mise en place de la dernière image */
404
int lastFrame = this->frame_number;
405
shots.back ().fduration = lastFrame - shots.back ().fbegin;
406
shots.back ().msduration = int (((shots.back ().fduration) * 1000) / fps);
407
duration.mstotal = int (shots.back ().msduration + shots.back ().msbegin);
408
image *end_i = new image (this, width, height, shots.back ().myid, END);
409
end_i->SaveFrame (pFrameRGB);
410
shots.back ().img_end = end_i;
413
* Graphe de la qté de mvmt
416
g->draw_all_canvas ();
417
g->draw_color_datas ();
421
string xml_color = graphpath + "/" + "video.xml";
422
g->write_xml (xml_color);
427
* Free the RGB images
433
av_free (pFrameRGBprev);
434
avcodec_close (pCodecCtx);
439
if (audioStream != -1)
441
/* Fermetrure du fichier xml */
442
if (audio_set) close_xml ();
443
avcodec_close (pCodecCtxAudio);
447
* Close the video file
449
av_close_input_file (pFormatCtx);
455
film::init_xml (string filename)
457
fd_xml_audio = fopen (filename.c_str (), "w");
458
fprintf (fd_xml_audio, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<iri>\n<sound sampling=\"%d\" nchannels=\"%d\">", samplearg, nchannel);
464
fprintf (fd_xml_audio, "</sound>\n</iri>");
465
return (fclose (fd_xml_audio));
470
film::process_audio ()
475
static unsigned int samples_size = 0;
484
this->audio_buf = (short *) av_fast_realloc (this->audio_buf, &samples_size, FFMAX (packet.size, AVCODEC_MAX_AUDIO_FRAME_SIZE));
485
data_size = samples_size;
486
len1 = avcodec_decode_audio2 (pCodecCtxAudio, audio_buf, &data_size, ptr, len);
492
* Error, breaking the frame
504
samples += data_size / (pCodecCtxAudio->channels * 2);
505
for (i = 0; i < data_size; i += 2 * pCodecCtxAudio->channels)
507
sample_right = *((signed short int *) (audio_buf + i));
509
* Si un seul canal, le sample droit = sample gauche
511
if (pCodecCtxAudio->channels >= 1)
512
sample_left = *((signed short int *) (audio_buf + i + 2));
514
sample_left = sample_right;
517
* extraction des minimas et maximas
519
if (minright > sample_right)
520
minright = sample_right;
521
if (maxright < sample_right)
522
maxright = sample_right;
523
if (minleft > sample_left)
524
minleft = sample_left;
525
if (maxleft < sample_left)
526
maxleft = sample_left;
531
if (ech++ == checknumber)
533
if (minright > minleft)
535
if (maxright > maxleft)
537
fprintf (fd_xml_audio, "<v c1d =\"%d\" c1u=\"%d\" />\n", minright / RATIO, maxright / RATIO);
544
* Reset sample number
564
this->first_img_set = false;
565
this->last_img_set = false;
566
this->audio_set = false;
567
this->video_set = false;
568
this->thumb_set = false;
569
this->shot_set = false;