Blender V2.61 - r43446

indexer.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * Peter Schlaile <peter [at] schlaile [dot] de> 2011
00019  *
00020  * Contributor(s): none yet.
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00025 #include "IMB_indexer.h"
00026 #include "IMB_anim.h"
00027 #include "AVI_avi.h"
00028 #include "imbuf.h"
00029 #include "MEM_guardedalloc.h"
00030 
00031 #include "BLI_utildefines.h"
00032 #include "BLI_blenlib.h"
00033 #include "BLI_math_base.h"
00034 
00035 #include "MEM_guardedalloc.h"
00036 #include "DNA_userdef_types.h"
00037 #include "BKE_global.h"
00038 #include <stdlib.h>
00039 
00040 #ifdef WITH_FFMPEG
00041 
00042 #include "ffmpeg_compat.h"
00043 
00044 #endif //WITH_FFMPEG
00045 
00046 
00047 static char magic[] = "BlenMIdx";
00048 static char temp_ext [] = "_part";
00049 
00050 static int proxy_sizes[] = { IMB_PROXY_25, IMB_PROXY_50, IMB_PROXY_75,
00051                              IMB_PROXY_100 };
00052 static float proxy_fac[] = { 0.25, 0.50, 0.75, 1.00 };
00053 
00054 #ifdef WITH_FFMPEG
00055 static int tc_types[] = { IMB_TC_RECORD_RUN,
00056                           IMB_TC_FREE_RUN,
00057                           IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN,
00058                           IMB_TC_RECORD_RUN_NO_GAPS,
00059                         };
00060 #endif
00061 
00062 #define INDEX_FILE_VERSION 1
00063 
00064 /* ---------------------------------------------------------------------- 
00065    - special indexers
00066    ---------------------------------------------------------------------- 
00067  */
00068 
00069 extern void IMB_indexer_dv_new(anim_index_builder * idx);
00070 
00071 
00072 /* ----------------------------------------------------------------------
00073    - time code index functions
00074    ---------------------------------------------------------------------- */
00075 
00076 anim_index_builder * IMB_index_builder_create(const char * name)
00077 {
00078 
00079     anim_index_builder * rv
00080             = MEM_callocN( sizeof(struct anim_index_builder),
00081                            "index builder");
00082 
00083     fprintf(stderr, "Starting work on index: %s\n", name);
00084 
00085     BLI_strncpy(rv->name, name, sizeof(rv->name));
00086     BLI_strncpy(rv->temp_name, name, sizeof(rv->temp_name));
00087 
00088     strcat(rv->temp_name, temp_ext);
00089 
00090     BLI_make_existing_file(rv->temp_name);
00091 
00092     rv->fp = fopen(rv->temp_name, "wb");
00093 
00094     if (!rv->fp) {
00095         fprintf(stderr, "Couldn't open index target: %s! "
00096             "Index build broken!\n", rv->temp_name);
00097         MEM_freeN(rv);
00098         return NULL;
00099     }
00100 
00101     fprintf(rv->fp, "%s%c%.3d", magic, (ENDIAN_ORDER==B_ENDIAN)?'V':'v',
00102         INDEX_FILE_VERSION);
00103 
00104     return rv;
00105 }
00106 
00107 void IMB_index_builder_add_entry(anim_index_builder * fp, 
00108                  int frameno, unsigned long long seek_pos,
00109                  unsigned long long seek_pos_dts,
00110                  unsigned long long pts)
00111 {
00112     fwrite(&frameno, sizeof(int), 1, fp->fp);
00113     fwrite(&seek_pos, sizeof(unsigned long long), 1, fp->fp);
00114     fwrite(&seek_pos_dts, sizeof(unsigned long long), 1, fp->fp);
00115     fwrite(&pts, sizeof(unsigned long long), 1, fp->fp);
00116 }
00117 
00118 void IMB_index_builder_proc_frame(anim_index_builder * fp, 
00119                   unsigned char * buffer,
00120                   int data_size,
00121                   int frameno, unsigned long long seek_pos,
00122                   unsigned long long seek_pos_dts,
00123                   unsigned long long pts)
00124 {
00125     if (fp->proc_frame) {
00126         anim_index_entry e;
00127         e.frameno = frameno;
00128         e.seek_pos = seek_pos;
00129         e.seek_pos_dts = seek_pos_dts;
00130         e.pts = pts;
00131 
00132         fp->proc_frame(fp, buffer, data_size, &e);
00133     } else {
00134         IMB_index_builder_add_entry(fp, frameno, seek_pos,
00135                         seek_pos_dts, pts);
00136     }
00137 }
00138 
00139 void IMB_index_builder_finish(anim_index_builder * fp, int rollback)
00140 {
00141     if (fp->delete_priv_data) {
00142         fp->delete_priv_data(fp);
00143     }
00144 
00145     fclose(fp->fp);
00146     
00147     if (rollback) {
00148         unlink(fp->temp_name);
00149     } else {
00150         rename(fp->temp_name, fp->name);
00151     }
00152 
00153     MEM_freeN(fp);
00154 }
00155 
00156 struct anim_index * IMB_indexer_open(const char * name)
00157 {
00158     char header[13];
00159     struct anim_index * idx;
00160     FILE * fp = fopen(name, "rb");
00161     int i;
00162 
00163     if (!fp) {
00164         return NULL;
00165     }
00166 
00167     if (fread(header, 12, 1, fp) != 1) {
00168         fclose(fp);
00169         return NULL;
00170     }
00171 
00172     header[12] = 0;
00173 
00174     if (memcmp(header, magic, 8) != 0) {
00175         fclose(fp);
00176         return NULL;
00177     }
00178 
00179     if (atoi(header+9) != INDEX_FILE_VERSION) {
00180         fclose(fp);
00181         return NULL;
00182     }
00183 
00184     idx = MEM_callocN( sizeof(struct anim_index), "anim_index");
00185 
00186     BLI_strncpy(idx->name, name, sizeof(idx->name));
00187     
00188     fseek(fp, 0, SEEK_END);
00189 
00190     idx->num_entries = (ftell(fp) - 12)
00191         / (sizeof(int) // framepos
00192            + sizeof(unsigned long long) // seek_pos
00193            + sizeof(unsigned long long) // seek_pos_dts
00194            + sizeof(unsigned long long) // pts
00195             );
00196     
00197     fseek(fp, 12, SEEK_SET);
00198 
00199     idx->entries = MEM_callocN( sizeof(struct anim_index_entry) 
00200                     * idx->num_entries, "anim_index_entries");
00201 
00202     for (i = 0; i < idx->num_entries; i++) {
00203         fread(&idx->entries[i].frameno,
00204               sizeof(int), 1, fp);
00205         fread(&idx->entries[i].seek_pos,
00206               sizeof(unsigned long long), 1, fp);
00207         fread(&idx->entries[i].seek_pos_dts,
00208               sizeof(unsigned long long), 1, fp);
00209         fread(&idx->entries[i].pts,
00210               sizeof(unsigned long long), 1, fp);
00211     }
00212 
00213     if (((ENDIAN_ORDER == B_ENDIAN) != (header[8] == 'V'))) {
00214         for (i = 0; i < idx->num_entries; i++) {
00215             SWITCH_INT(idx->entries[i].frameno);
00216             SWITCH_INT64(idx->entries[i].seek_pos);
00217             SWITCH_INT64(idx->entries[i].seek_pos_dts);
00218             SWITCH_INT64(idx->entries[i].pts);
00219         }
00220     }
00221 
00222     fclose(fp);
00223 
00224     return idx;
00225 }
00226 
00227 unsigned long long IMB_indexer_get_seek_pos(
00228     struct anim_index * idx, int frame_index)
00229 {
00230     if (frame_index < 0) {
00231         frame_index = 0;
00232     }
00233     if (frame_index >= idx->num_entries) {
00234         frame_index = idx->num_entries - 1;
00235     }
00236     return idx->entries[frame_index].seek_pos;
00237 }
00238 
00239 unsigned long long IMB_indexer_get_seek_pos_dts(
00240     struct anim_index * idx, int frame_index)
00241 {
00242     if (frame_index < 0) {
00243         frame_index = 0;
00244     }
00245     if (frame_index >= idx->num_entries) {
00246         frame_index = idx->num_entries - 1;
00247     }
00248     return idx->entries[frame_index].seek_pos_dts;
00249 }
00250 
00251 int IMB_indexer_get_frame_index(struct anim_index * idx, int frameno)
00252 {
00253     int len = idx->num_entries;
00254     int half;
00255     int middle;
00256     int first = 0;
00257 
00258     /* bsearch (lower bound) the right index */
00259     
00260     while (len > 0) {
00261         half = len >> 1;
00262         middle = first;
00263 
00264         middle += half;
00265 
00266         if (idx->entries[middle].frameno < frameno) {
00267             first = middle;
00268             ++first;
00269             len = len - half - 1;
00270         } else {
00271             len = half;
00272         }
00273     }
00274 
00275     if (first == idx->num_entries) {
00276         return idx->num_entries - 1;
00277     } else {
00278         return first;
00279     }
00280 }
00281 
00282 unsigned long long IMB_indexer_get_pts(struct anim_index * idx, 
00283                        int frame_index)
00284 {
00285     if (frame_index < 0) {
00286         frame_index = 0;
00287     }
00288     if (frame_index >= idx->num_entries) {
00289         frame_index = idx->num_entries - 1;
00290     }
00291     return idx->entries[frame_index].pts;
00292 }
00293 
00294 int IMB_indexer_get_duration(struct anim_index * idx)
00295 {
00296     if (idx->num_entries == 0) {
00297         return 0;
00298     }
00299     return idx->entries[idx->num_entries-1].frameno + 1;
00300 }
00301 
00302 int IMB_indexer_can_scan(struct anim_index * idx, 
00303              int old_frame_index, int new_frame_index)
00304 {
00305     /* makes only sense, if it is the same I-Frame and we are not
00306        trying to run backwards in time... */
00307     return (IMB_indexer_get_seek_pos(idx, old_frame_index)
00308         == IMB_indexer_get_seek_pos(idx, new_frame_index) && 
00309         old_frame_index < new_frame_index);
00310 }
00311 
00312 void IMB_indexer_close(struct anim_index * idx)
00313 {
00314     MEM_freeN(idx->entries);
00315     MEM_freeN(idx);
00316 }
00317 
00318 int IMB_proxy_size_to_array_index(IMB_Proxy_Size pr_size)
00319 {
00320     switch (pr_size) {
00321     case IMB_PROXY_NONE: /* if we got here, something is broken anyways,
00322                 so sane defaults... */
00323         return 0;
00324     case IMB_PROXY_25:
00325         return 0;
00326     case IMB_PROXY_50:
00327         return 1;
00328     case IMB_PROXY_75:
00329         return 2;
00330     case IMB_PROXY_100:
00331         return 3;
00332     default:
00333         return 0;
00334     };
00335     return 0;
00336 }
00337 
00338 int IMB_timecode_to_array_index(IMB_Timecode_Type tc)
00339 {
00340     switch (tc) {
00341     case IMB_TC_NONE: /* if we got here, something is broken anyways,
00342                 so sane defaults... */
00343         return 0;
00344     case IMB_TC_RECORD_RUN:
00345         return 0;
00346     case IMB_TC_FREE_RUN:
00347         return 1;
00348     case IMB_TC_INTERPOLATED_REC_DATE_FREE_RUN:
00349         return 2;
00350     case IMB_TC_RECORD_RUN_NO_GAPS:
00351         return 3;
00352     default:
00353         return 0;
00354     };
00355     return 0;
00356 }
00357 
00358 
00359 /* ----------------------------------------------------------------------
00360    - rebuild helper functions
00361    ---------------------------------------------------------------------- */
00362 
00363 static void get_index_dir(struct anim * anim, char * index_dir)
00364 {
00365     if (!anim->index_dir[0]) {
00366         char fname[FILE_MAXFILE];
00367         BLI_strncpy(index_dir, anim->name, FILE_MAXDIR);
00368         BLI_splitdirstring(index_dir, fname);
00369         BLI_join_dirfile(index_dir, FILE_MAXDIR, index_dir, "BL_proxy");
00370         BLI_join_dirfile(index_dir, FILE_MAXDIR, index_dir, fname);
00371     } else {
00372         BLI_strncpy(index_dir, anim->index_dir, FILE_MAXDIR);
00373     }
00374 }
00375 
00376 static void get_proxy_filename(struct anim * anim, IMB_Proxy_Size preview_size,
00377                    char * fname, int temp)
00378 {
00379     char index_dir[FILE_MAXDIR];
00380     int i = IMB_proxy_size_to_array_index(preview_size);
00381 
00382     char proxy_name[256];
00383     char proxy_temp_name[256];
00384     char stream_suffix[20];
00385     
00386     stream_suffix[0] = 0;
00387 
00388     if (anim->streamindex > 0) {
00389         BLI_snprintf(stream_suffix, sizeof(stream_suffix), "_st%d", anim->streamindex);
00390     }
00391 
00392     BLI_snprintf(proxy_name, sizeof(proxy_name), "proxy_%d%s.avi",
00393              (int) (proxy_fac[i] * 100), stream_suffix);
00394     BLI_snprintf(proxy_temp_name, sizeof(proxy_temp_name), "proxy_%d%s_part.avi",
00395              (int) (proxy_fac[i] * 100), stream_suffix);
00396 
00397     get_index_dir(anim, index_dir);
00398 
00399     BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, 
00400                      temp ? proxy_temp_name : proxy_name);
00401 }
00402 
00403 static void get_tc_filename(struct anim * anim, IMB_Timecode_Type tc,
00404                 char * fname)
00405 {
00406     char index_dir[FILE_MAXDIR];
00407     int i = IMB_timecode_to_array_index(tc);
00408     const char * index_names[] = {
00409         "record_run%s.blen_tc",
00410         "free_run%s.blen_tc",
00411         "interp_free_run%s.blen_tc",
00412         "record_run_no_gaps%s.blen_tc"};
00413 
00414     char stream_suffix[20];
00415     char index_name[256];
00416     
00417     stream_suffix[0] = 0;
00418 
00419     if (anim->streamindex > 0) {
00420         BLI_snprintf(stream_suffix, 20, "_st%d", anim->streamindex);
00421     }
00422     
00423     BLI_snprintf(index_name, 256, index_names[i], stream_suffix);
00424 
00425     get_index_dir(anim, index_dir);
00426     
00427     BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, 
00428                      index_dir, index_name);
00429 }
00430 
00431 /* ----------------------------------------------------------------------
00432    - ffmpeg rebuilder
00433    ---------------------------------------------------------------------- */
00434 
00435 #ifdef WITH_FFMPEG
00436 
00437 struct proxy_output_ctx {
00438     AVFormatContext* of;
00439     AVStream* st;
00440     AVCodecContext* c;
00441     AVCodec* codec;
00442     struct SwsContext * sws_ctx;
00443     AVFrame* frame;
00444     uint8_t* video_buffer;
00445     int video_buffersize;
00446     int cfra;
00447     int proxy_size;
00448     int orig_height;
00449     struct anim * anim;
00450 };
00451 
00452 // work around stupid swscaler 16 bytes alignment bug...
00453 
00454 static int round_up(int x, int mod)
00455 {
00456     return x + ((mod - (x % mod)) % mod);
00457 }
00458 
00459 static struct proxy_output_ctx * alloc_proxy_output_ffmpeg(
00460     struct anim * anim,
00461     AVStream * st, int proxy_size, int width, int height,
00462     int UNUSED(quality))
00463 {
00464     struct proxy_output_ctx * rv = MEM_callocN(
00465         sizeof(struct proxy_output_ctx), "alloc_proxy_output");
00466     
00467     char fname[FILE_MAX];
00468 
00469     // JPEG requires this
00470     width = round_up(width, 8);
00471     height = round_up(height, 8);
00472 
00473     rv->proxy_size = proxy_size;
00474     rv->anim = anim;
00475 
00476     get_proxy_filename(rv->anim, rv->proxy_size, fname, TRUE);
00477     BLI_make_existing_file(fname);
00478 
00479     rv->of = avformat_alloc_context();
00480     rv->of->oformat = av_guess_format("avi", NULL, NULL);
00481     
00482     BLI_snprintf(rv->of->filename, sizeof(rv->of->filename), "%s", fname);
00483 
00484     fprintf(stderr, "Starting work on proxy: %s\n", rv->of->filename);
00485 
00486     rv->st = av_new_stream(rv->of, 0);
00487     rv->c = rv->st->codec;
00488     rv->c->codec_type = AVMEDIA_TYPE_VIDEO;
00489     rv->c->codec_id = CODEC_ID_MJPEG;
00490     rv->c->width = width;
00491     rv->c->height = height;
00492 
00493     rv->of->oformat->video_codec = rv->c->codec_id;
00494     rv->codec = avcodec_find_encoder(rv->c->codec_id);
00495 
00496     if (!rv->codec) {
00497         fprintf(stderr, "No ffmpeg MJPEG encoder available? "
00498             "Proxy not built!\n");
00499         av_free(rv->of);
00500         return NULL;
00501     }
00502 
00503     if (rv->codec->pix_fmts) {
00504         rv->c->pix_fmt = rv->codec->pix_fmts[0];
00505     } else {
00506         rv->c->pix_fmt = PIX_FMT_YUVJ420P;
00507     }
00508 
00509     rv->c->sample_aspect_ratio 
00510         = rv->st->sample_aspect_ratio 
00511         = st->codec->sample_aspect_ratio;
00512 
00513     rv->c->time_base.den = 25;
00514     rv->c->time_base.num = 1;
00515     rv->st->time_base = rv->c->time_base;
00516 
00517     if (rv->of->flags & AVFMT_GLOBALHEADER) {
00518         rv->c->flags |= CODEC_FLAG_GLOBAL_HEADER;
00519     }
00520 
00521     if (av_set_parameters(rv->of, NULL) < 0) {
00522         fprintf(stderr, "Couldn't set output parameters? "
00523             "Proxy not built!\n");
00524         av_free(rv->of);
00525         return 0;
00526     }
00527 
00528     if (avio_open(&rv->of->pb, fname, AVIO_FLAG_WRITE) < 0) {
00529         fprintf(stderr, "Couldn't open outputfile! "
00530             "Proxy not built!\n");
00531         av_free(rv->of);
00532         return 0;
00533     }
00534 
00535     avcodec_open(rv->c, rv->codec);
00536 
00537     rv->video_buffersize = 2000000;
00538     rv->video_buffer = (uint8_t*)MEM_mallocN(
00539         rv->video_buffersize, "FFMPEG video buffer");
00540 
00541     rv->orig_height = st->codec->height;
00542 
00543     if (st->codec->width != width || st->codec->height != height ||
00544             st->codec->pix_fmt != rv->c->pix_fmt)
00545     {
00546         rv->frame = avcodec_alloc_frame();
00547         avpicture_fill((AVPicture*) rv->frame,
00548                        MEM_mallocN(avpicture_get_size(
00549                                        rv->c->pix_fmt,
00550                                        round_up(width, 16), height),
00551                                    "alloc proxy output frame"),
00552                        rv->c->pix_fmt, round_up(width, 16), height);
00553 
00554         rv->sws_ctx = sws_getContext(
00555             st->codec->width,
00556             st->codec->height,
00557             st->codec->pix_fmt,
00558             width, height,
00559             rv->c->pix_fmt,
00560             SWS_FAST_BILINEAR | SWS_PRINT_INFO,
00561             NULL, NULL, NULL);
00562     }
00563 
00564     av_write_header(rv->of);
00565 
00566     return rv;
00567 }
00568 
00569 static int add_to_proxy_output_ffmpeg(
00570     struct proxy_output_ctx * ctx, AVFrame * frame)
00571 {
00572     int outsize = 0;
00573 
00574     if (!ctx) {
00575         return 0;
00576     }
00577 
00578     if (    ctx->sws_ctx && frame &&
00579             (frame->data[0] || frame->data[1] ||
00580              frame->data[2] || frame->data[3]))
00581     {
00582         sws_scale(ctx->sws_ctx, (const uint8_t * const*) frame->data,
00583                   frame->linesize, 0, ctx->orig_height,
00584                   ctx->frame->data, ctx->frame->linesize);
00585     }
00586 
00587     frame = ctx->sws_ctx ? (frame ? ctx->frame : 0) : frame;
00588 
00589     if (frame) {
00590         frame->pts = ctx->cfra++;
00591     }
00592 
00593     outsize = avcodec_encode_video(
00594         ctx->c, ctx->video_buffer, ctx->video_buffersize, 
00595         frame);
00596 
00597     if (outsize < 0) {
00598         fprintf(stderr, "Error encoding proxy frame %d for '%s'\n", 
00599             ctx->cfra - 1, ctx->of->filename);
00600         return 0;
00601     }
00602 
00603     if (outsize != 0) {
00604         AVPacket packet;
00605         av_init_packet(&packet);
00606 
00607         if (ctx->c->coded_frame->pts != AV_NOPTS_VALUE) {
00608             packet.pts = av_rescale_q(ctx->c->coded_frame->pts,
00609                           ctx->c->time_base,
00610                           ctx->st->time_base);
00611         }
00612         if (ctx->c->coded_frame->key_frame)
00613             packet.flags |= AV_PKT_FLAG_KEY;
00614 
00615         packet.stream_index = ctx->st->index;
00616         packet.data = ctx->video_buffer;
00617         packet.size = outsize;
00618 
00619         if (av_interleaved_write_frame(ctx->of, &packet) != 0) {
00620             fprintf(stderr, "Error writing proxy frame %d "
00621                 "into '%s'\n", ctx->cfra - 1, 
00622                 ctx->of->filename);
00623             return 0;
00624         }
00625 
00626         return 1;
00627     } else {
00628         return 0;
00629     }
00630 }
00631 
00632 static void free_proxy_output_ffmpeg(struct proxy_output_ctx * ctx,
00633                      int rollback)
00634 {
00635     int i;
00636     char fname[FILE_MAX];
00637     char fname_tmp[FILE_MAX];
00638 
00639     if (!ctx) {
00640         return;
00641     }
00642 
00643     if (!rollback) {
00644         while (add_to_proxy_output_ffmpeg(ctx, NULL)) ;
00645     }
00646 
00647     avcodec_flush_buffers(ctx->c);
00648 
00649     av_write_trailer(ctx->of);
00650     
00651     avcodec_close(ctx->c);
00652     
00653     for (i = 0; i < ctx->of->nb_streams; i++) {
00654         if (&ctx->of->streams[i]) {
00655             av_freep(&ctx->of->streams[i]);
00656         }
00657     }
00658 
00659     if (ctx->of->oformat) {
00660         if (!(ctx->of->oformat->flags & AVFMT_NOFILE)) {
00661             avio_close(ctx->of->pb);
00662         }
00663     }
00664     av_free(ctx->of);
00665 
00666     MEM_freeN(ctx->video_buffer);
00667 
00668     if (ctx->sws_ctx) {
00669         sws_freeContext(ctx->sws_ctx);
00670 
00671         MEM_freeN(ctx->frame->data[0]);
00672         av_free(ctx->frame);
00673     }
00674 
00675     get_proxy_filename(ctx->anim, ctx->proxy_size, 
00676                        fname_tmp, TRUE);
00677 
00678     if (rollback) {
00679         unlink(fname_tmp);
00680     } else {
00681         get_proxy_filename(ctx->anim, ctx->proxy_size, 
00682                            fname, FALSE);
00683         rename(fname_tmp, fname);
00684     }
00685     
00686     MEM_freeN(ctx);
00687 }
00688 
00689 
00690 static int index_rebuild_ffmpeg(struct anim * anim, 
00691                 IMB_Timecode_Type tcs_in_use,
00692                 IMB_Proxy_Size proxy_sizes_in_use,
00693                 int quality,
00694                 short *stop, short *do_update, 
00695                 float *progress)
00696 {
00697     int i, videoStream;
00698     unsigned long long seek_pos = 0;
00699     unsigned long long last_seek_pos = 0;
00700     unsigned long long seek_pos_dts = 0;
00701     unsigned long long seek_pos_pts = 0;
00702     unsigned long long last_seek_pos_dts = 0;
00703     unsigned long long start_pts = 0;
00704     double frame_rate;
00705     double pts_time_base;
00706     int frameno = 0, frameno_gapless = 0;
00707     int start_pts_set = FALSE;
00708 
00709     AVFormatContext *iFormatCtx;
00710     AVCodecContext *iCodecCtx;
00711     AVCodec *iCodec;
00712     AVStream *iStream;
00713     AVFrame* in_frame = 0;
00714     AVPacket next_packet;
00715     int streamcount;
00716 
00717     struct proxy_output_ctx * proxy_ctx[IMB_PROXY_MAX_SLOT];
00718     anim_index_builder * indexer [IMB_TC_MAX_SLOT];
00719 
00720     int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
00721     int num_indexers = IMB_TC_MAX_SLOT;
00722     uint64_t stream_size;
00723 
00724     memset(proxy_ctx, 0, sizeof(proxy_ctx));
00725     memset(indexer, 0, sizeof(indexer));
00726 
00727     if(av_open_input_file(&iFormatCtx, anim->name, NULL, 0, NULL) != 0) {
00728         return 0;
00729     }
00730 
00731     if (av_find_stream_info(iFormatCtx) < 0) {
00732         av_close_input_file(iFormatCtx);
00733         return 0;
00734     }
00735 
00736     streamcount = anim->streamindex;
00737 
00738     /* Find the video stream */
00739     videoStream = -1;
00740     for (i = 0; i < iFormatCtx->nb_streams; i++)
00741         if(iFormatCtx->streams[i]->codec->codec_type
00742            == AVMEDIA_TYPE_VIDEO) {
00743             if (streamcount > 0) {
00744                 streamcount--;
00745                 continue;
00746             }
00747             videoStream = i;
00748             break;
00749         }
00750 
00751     if (videoStream == -1) {
00752         av_close_input_file(iFormatCtx);
00753         return 0;
00754     }
00755 
00756     iStream = iFormatCtx->streams[videoStream];
00757     iCodecCtx = iStream->codec;
00758 
00759     iCodec = avcodec_find_decoder(iCodecCtx->codec_id);
00760     
00761     if (iCodec == NULL) {
00762         av_close_input_file(iFormatCtx);
00763         return 0;
00764     }
00765 
00766     iCodecCtx->workaround_bugs = 1;
00767 
00768     if (avcodec_open(iCodecCtx, iCodec) < 0) {
00769         av_close_input_file(iFormatCtx);
00770         return 0;
00771     }
00772 
00773     in_frame = avcodec_alloc_frame();
00774 
00775     stream_size = avio_size(iFormatCtx->pb);
00776 
00777     for (i = 0; i < num_proxy_sizes; i++) {
00778         if (proxy_sizes_in_use & proxy_sizes[i]) {
00779             proxy_ctx[i] = alloc_proxy_output_ffmpeg(
00780                 anim, iStream, proxy_sizes[i],
00781                 iCodecCtx->width * proxy_fac[i],
00782                 iCodecCtx->height * proxy_fac[i],
00783                 quality);
00784             if (!proxy_ctx[i]) {
00785                 proxy_sizes_in_use &= ~proxy_sizes[i];
00786             }
00787         }
00788     }
00789 
00790     for (i = 0; i < num_indexers; i++) {
00791         if (tcs_in_use & tc_types[i]) {
00792             char fname[FILE_MAX];
00793 
00794             get_tc_filename(anim, tc_types[i], fname);
00795 
00796             indexer[i] = IMB_index_builder_create(fname);
00797             if (!indexer[i]) {
00798                 tcs_in_use &= ~tc_types[i];
00799             }
00800         }
00801     }
00802 
00803     frame_rate = av_q2d(iStream->r_frame_rate);
00804     pts_time_base = av_q2d(iStream->time_base);
00805 
00806     while(av_read_frame(iFormatCtx, &next_packet) >= 0) {
00807         int frame_finished = 0;
00808         float next_progress =  (float)((int)floor(((double) next_packet.pos) * 100 /
00809                                            ((double) stream_size)+0.5)) / 100;
00810 
00811         if (*progress != next_progress) {
00812             *progress = next_progress;
00813             *do_update = 1;
00814         }
00815 
00816         if (*stop) {
00817             av_free_packet(&next_packet);
00818             break;
00819         }
00820 
00821         if (next_packet.stream_index == videoStream) {
00822             if (next_packet.flags & AV_PKT_FLAG_KEY) {
00823                 last_seek_pos = seek_pos;
00824                 last_seek_pos_dts = seek_pos_dts;
00825                 seek_pos = next_packet.pos;
00826                 seek_pos_dts = next_packet.dts;
00827                 seek_pos_pts = next_packet.pts;
00828             }
00829 
00830             avcodec_decode_video2(
00831                 iCodecCtx, in_frame, &frame_finished, 
00832                 &next_packet);
00833         }
00834 
00835         if (frame_finished) {
00836             unsigned long long s_pos = seek_pos;
00837             unsigned long long s_dts = seek_pos_dts;
00838             unsigned long long pts 
00839                 = av_get_pts_from_frame(iFormatCtx, in_frame);
00840 
00841             for (i = 0; i < num_proxy_sizes; i++) {
00842                 add_to_proxy_output_ffmpeg(
00843                     proxy_ctx[i], in_frame);
00844             }
00845 
00846             if (!start_pts_set) {
00847                 start_pts = pts;
00848                 start_pts_set = TRUE;
00849             }
00850 
00851             frameno = floor((pts - start_pts)
00852                 * pts_time_base * frame_rate + 0.5f);
00853 
00854             /* decoding starts *always* on I-Frames,
00855                so: P-Frames won't work, even if all the
00856                information is in place, when we seek
00857                to the I-Frame presented *after* the P-Frame,
00858                but located before the P-Frame within
00859                the stream */
00860 
00861             if (pts < seek_pos_pts) {
00862                 s_pos = last_seek_pos;
00863                 s_dts = last_seek_pos_dts;
00864             }
00865 
00866             for (i = 0; i < num_indexers; i++) {
00867                 if (tcs_in_use & tc_types[i]) {
00868                     int tc_frameno = frameno;
00869 
00870                     if(tc_types[i] == IMB_TC_RECORD_RUN_NO_GAPS)
00871                         tc_frameno = frameno_gapless;
00872 
00873                     IMB_index_builder_proc_frame(
00874                         indexer[i], 
00875                         next_packet.data, 
00876                         next_packet.size,
00877                         tc_frameno,
00878                         s_pos, s_dts, pts);
00879                 }
00880             }
00881 
00882             frameno_gapless++;
00883         }
00884         av_free_packet(&next_packet);
00885     }
00886 
00887     for (i = 0; i < num_indexers; i++) {
00888         if (tcs_in_use & tc_types[i]) {
00889             IMB_index_builder_finish(indexer[i], *stop);
00890         }
00891     }
00892 
00893     for (i = 0; i < num_proxy_sizes; i++) {
00894         if (proxy_sizes_in_use & proxy_sizes[i]) {
00895             free_proxy_output_ffmpeg(proxy_ctx[i], *stop);
00896         }
00897     }
00898 
00899     av_free(in_frame);
00900 
00901     return 1;
00902 }
00903 
00904 #endif
00905 
00906 /* ----------------------------------------------------------------------
00907    - internal AVI (fallback) rebuilder
00908    ---------------------------------------------------------------------- */
00909 
00910 static AviMovie * alloc_proxy_output_avi(
00911     struct anim * anim, char * filename, int width, int height,
00912     int quality)
00913 {
00914     int x, y;
00915     AviFormat format;
00916     double framerate;
00917     AviMovie * avi;
00918     short frs_sec = 25;      /* it doesn't really matter for proxies,
00919                     but sane defaults help anyways...*/
00920     float frs_sec_base = 1.0;
00921 
00922     IMB_anim_get_fps(anim, &frs_sec, &frs_sec_base);
00923     
00924     x = width;
00925     y = height;
00926 
00927     framerate= (double) frs_sec / (double) frs_sec_base;
00928     
00929     avi = MEM_mallocN (sizeof(AviMovie), "avimovie");
00930 
00931     format = AVI_FORMAT_MJPEG;
00932 
00933     if (AVI_open_compress (filename, avi, 1, format) != AVI_ERROR_NONE) {
00934         MEM_freeN(avi);
00935         return NULL;
00936     }
00937             
00938     AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x);
00939     AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y);
00940     AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality);       
00941     AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate);
00942 
00943     avi->interlace= 0;
00944     avi->odd_fields= 0;
00945 
00946     return avi;
00947 }
00948 
00949 static void index_rebuild_fallback(struct anim * anim,
00950                    IMB_Timecode_Type UNUSED(tcs_in_use),
00951                    IMB_Proxy_Size proxy_sizes_in_use,
00952                    int quality,
00953                    short *stop, short *do_update, 
00954                    float *progress)
00955 {
00956     int cnt = IMB_anim_get_duration(anim, IMB_TC_NONE);
00957     int i, pos;
00958     AviMovie * proxy_ctx[IMB_PROXY_MAX_SLOT];
00959     char fname[FILE_MAX];
00960     char fname_tmp[FILE_MAX];
00961     
00962     memset(proxy_ctx, 0, sizeof(proxy_ctx));
00963 
00964     /* since timecode indices only work with ffmpeg right now,
00965        don't know a sensible fallback here...
00966 
00967        so no proxies, no game to play...
00968     */
00969     if (proxy_sizes_in_use == IMB_PROXY_NONE) {
00970         return;
00971     }
00972 
00973     for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
00974         if (proxy_sizes_in_use & proxy_sizes[i]) {
00975             char fname[FILE_MAX];
00976 
00977             get_proxy_filename(anim, proxy_sizes[i], fname, TRUE);
00978             BLI_make_existing_file(fname);
00979 
00980             proxy_ctx[i] = alloc_proxy_output_avi(
00981                 anim, fname,
00982                 anim->x * proxy_fac[i],
00983                 anim->y * proxy_fac[i],
00984                 quality);
00985         }
00986     }
00987 
00988     for (pos = 0; pos < cnt; pos++) {
00989         struct ImBuf * ibuf = IMB_anim_absolute(
00990             anim, pos, IMB_TC_NONE, IMB_PROXY_NONE);
00991         int next_progress = (int) ((double) pos / (double) cnt);
00992 
00993         if (*progress != next_progress) {
00994             *progress = next_progress;
00995             *do_update = 1;
00996         }
00997         
00998         if (*stop) {
00999             break;
01000         }
01001 
01002         IMB_flipy(ibuf);
01003 
01004         for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
01005             if (proxy_sizes_in_use & proxy_sizes[i]) {
01006                 int x = anim->x * proxy_fac[i];
01007                 int y = anim->y * proxy_fac[i];
01008 
01009                 struct ImBuf * s_ibuf = IMB_scalefastImBuf(
01010                     ibuf, x, y);
01011 
01012                 IMB_convert_rgba_to_abgr(s_ibuf);
01013     
01014                 AVI_write_frame (proxy_ctx[i], pos, 
01015                          AVI_FORMAT_RGB32, 
01016                          s_ibuf->rect, x * y * 4);
01017 
01018                 /* note that libavi free's the buffer... */
01019                 s_ibuf->rect = NULL;
01020 
01021                 IMB_freeImBuf(s_ibuf);
01022             }
01023         }
01024     }
01025 
01026     for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
01027         if (proxy_sizes_in_use & proxy_sizes[i]) {
01028             AVI_close_compress (proxy_ctx[i]);
01029             MEM_freeN (proxy_ctx[i]);
01030 
01031             get_proxy_filename(anim, proxy_sizes[i], 
01032                        fname_tmp, TRUE);
01033             get_proxy_filename(anim, proxy_sizes[i], 
01034                        fname, FALSE);
01035 
01036             if (*stop) {
01037                 unlink(fname_tmp);
01038             } else {
01039                 rename(fname_tmp, fname);
01040             }
01041         }
01042     }
01043 }
01044 
01045 /* ----------------------------------------------------------------------
01046    - public API
01047    ---------------------------------------------------------------------- */
01048 
01049 void IMB_anim_index_rebuild(struct anim * anim, IMB_Timecode_Type tcs_in_use,
01050                 IMB_Proxy_Size proxy_sizes_in_use,
01051                 int quality,
01052                 short *stop, short *do_update, float *progress)
01053 {
01054     switch (anim->curtype) {
01055 #ifdef WITH_FFMPEG
01056     case ANIM_FFMPEG:
01057         index_rebuild_ffmpeg(anim, tcs_in_use, proxy_sizes_in_use,
01058                      quality, stop, do_update, progress);
01059         break;
01060 #endif
01061     default:
01062         index_rebuild_fallback(anim, tcs_in_use, proxy_sizes_in_use,
01063                        quality, stop, do_update, progress);
01064         break;
01065     }
01066 }
01067 
01068 void IMB_free_indices(struct anim * anim)
01069 {
01070     int i;
01071 
01072     for (i = 0; i < IMB_PROXY_MAX_SLOT; i++) {
01073         if (anim->proxy_anim[i]) {
01074             IMB_close_anim(anim->proxy_anim[i]);
01075             anim->proxy_anim[i] = NULL;
01076         }
01077     }
01078 
01079     for (i = 0; i < IMB_TC_MAX_SLOT; i++) {
01080         if (anim->curr_idx[i]) {
01081             IMB_indexer_close(anim->curr_idx[i]);
01082             anim->curr_idx[i] = NULL;
01083         }
01084     }
01085 
01086 
01087     anim->proxies_tried = 0;
01088     anim->indices_tried = 0;
01089 }
01090 
01091 void IMB_anim_set_index_dir(struct anim * anim, const char * dir)
01092 {
01093     if (strcmp(anim->index_dir, dir) == 0) {
01094         return;
01095     }
01096     BLI_strncpy(anim->index_dir, dir, sizeof(anim->index_dir));
01097 
01098     IMB_free_indices(anim);
01099 }
01100 
01101 struct anim * IMB_anim_open_proxy(
01102     struct anim * anim, IMB_Proxy_Size preview_size)
01103 {
01104     char fname[FILE_MAX];
01105     int i = IMB_proxy_size_to_array_index(preview_size);
01106 
01107     if (anim->proxy_anim[i]) {
01108         return anim->proxy_anim[i];
01109     }
01110 
01111     if (anim->proxies_tried & preview_size) {
01112         return NULL;
01113     }
01114 
01115     get_proxy_filename(anim, preview_size, fname, FALSE);
01116 
01117     anim->proxy_anim[i] = IMB_open_anim(fname, 0, 0);
01118     
01119     anim->proxies_tried |= preview_size;
01120 
01121     return anim->proxy_anim[i];
01122 }
01123 
01124 struct anim_index * IMB_anim_open_index(
01125     struct anim * anim, IMB_Timecode_Type tc)
01126 {
01127     char fname[FILE_MAX];
01128     int i = IMB_timecode_to_array_index(tc);
01129 
01130     if (anim->curr_idx[i]) {
01131         return anim->curr_idx[i];
01132     }
01133 
01134     if (anim->indices_tried & tc) {
01135         return NULL;
01136     }
01137 
01138     get_tc_filename(anim, tc, fname);
01139 
01140     anim->curr_idx[i] = IMB_indexer_open(fname);
01141     
01142     anim->indices_tried |= tc;
01143 
01144     return anim->curr_idx[i];
01145 }
01146 
01147 int IMB_anim_index_get_frame_index(struct anim * anim, IMB_Timecode_Type tc,
01148                    int position)
01149 {
01150     struct anim_index * idx = IMB_anim_open_index(anim, tc);
01151 
01152     if (!idx) {
01153         return position;
01154     }
01155 
01156     return IMB_indexer_get_frame_index(idx, position);
01157 }
01158