static void ffmpeg_postprocess(struct anim *anim) { AVFrame *input = anim->pFrame; ImBuf *ibuf = anim->last_frame; int filter_y = 0; if (!anim->pFrameComplete) { return; } /* This means the data wasnt read properly, * this check stops crashing */ if (input->data[0] == 0 && input->data[1] == 0 && input->data[2] == 0 && input->data[3] == 0) { fprintf(stderr, "ffmpeg_fetchibuf: " "data not read properly...\n"); return; } av_log(anim->pFormatCtx, AV_LOG_DEBUG, " POSTPROC: anim->pFrame planes: %p %p %p %p\n", input->data[0], input->data[1], input->data[2], input->data[3]); if (anim->ib_flags & IB_animdeinterlace) { if (avpicture_deinterlace( (AVPicture *) anim->pFrameDeinterlaced, (const AVPicture *) anim->pFrame, anim->pCodecCtx->pix_fmt, anim->pCodecCtx->width, anim->pCodecCtx->height) < 0) { filter_y = TRUE; } else { input = anim->pFrameDeinterlaced; } } avpicture_fill((AVPicture *) anim->pFrameRGB, (unsigned char *) ibuf->rect, PIX_FMT_RGBA, anim->x, anim->y); if (ENDIAN_ORDER == B_ENDIAN) { int *dstStride = anim->pFrameRGB->linesize; uint8_t **dst = anim->pFrameRGB->data; int dstStride2[4] = { dstStride[0], 0, 0, 0 }; uint8_t *dst2[4] = { dst[0], 0, 0, 0 }; int x, y, h, w; unsigned char *bottom; unsigned char *top; sws_scale(anim->img_convert_ctx, (const uint8_t *const *)input->data, input->linesize, 0, anim->y, dst2, dstStride2); bottom = (unsigned char *) ibuf->rect; top = bottom + ibuf->x * (ibuf->y - 1) * 4; h = (ibuf->y + 1) / 2; w = ibuf->x; for (y = 0; y < h; y++) { unsigned char tmp[4]; unsigned int *tmp_l = (unsigned int *) tmp; for (x = 0; x < w; x++) { tmp[0] = bottom[0]; tmp[1] = bottom[1]; tmp[2] = bottom[2]; tmp[3] = bottom[3]; bottom[0] = top[0]; bottom[1] = top[1]; bottom[2] = top[2]; bottom[3] = top[3]; *(unsigned int *) top = *tmp_l; bottom += 4; top += 4; } top -= 8 * w; } } else { int *dstStride = anim->pFrameRGB->linesize; uint8_t **dst = anim->pFrameRGB->data; int dstStride2[4] = { -dstStride[0], 0, 0, 0 }; uint8_t *dst2[4] = { dst[0] + (anim->y - 1) * dstStride[0], 0, 0, 0 }; sws_scale(anim->img_convert_ctx, (const uint8_t *const *)input->data, input->linesize, 0, anim->y, dst2, dstStride2); } if (filter_y) { IMB_filtery(ibuf); } }
struct ImBuf *IMB_anim_absolute(struct anim *anim, int position, IMB_Timecode_Type tc, IMB_Proxy_Size preview_size) { struct ImBuf *ibuf = NULL; char head[256], tail[256]; unsigned short digits; int pic; int filter_y; if (anim == NULL) return(NULL); filter_y = (anim->ib_flags & IB_animdeinterlace); if (anim->curtype == 0) { ibuf = anim_getnew(anim); if (ibuf == NULL) { return(NULL); } IMB_freeImBuf(ibuf); /* ???? */ ibuf = NULL; } if (position < 0) return(NULL); if (position >= anim->duration) return(NULL); if (preview_size != IMB_PROXY_NONE) { struct anim *proxy = IMB_anim_open_proxy(anim, preview_size); if (proxy) { position = IMB_anim_index_get_frame_index( anim, tc, position); return IMB_anim_absolute( proxy, position, IMB_TC_NONE, IMB_PROXY_NONE); } } switch (anim->curtype) { case ANIM_SEQUENCE: pic = an_stringdec(anim->first, head, tail, &digits); pic += position; an_stringenc(anim->name, head, tail, digits, pic); ibuf = IMB_loadiffname(anim->name, IB_rect, anim->colorspace); if (ibuf) { anim->curposition = position; } break; case ANIM_MOVIE: ibuf = movie_fetchibuf(anim, position); if (ibuf) { anim->curposition = position; IMB_convert_rgba_to_abgr(ibuf); } break; #ifdef WITH_AVI case ANIM_AVI: ibuf = avi_fetchibuf(anim, position); if (ibuf) anim->curposition = position; break; #endif #ifdef WITH_QUICKTIME case ANIM_QTIME: ibuf = qtime_fetchibuf(anim, position); if (ibuf) { if (ibuf->rect) { /* OCIO_TODO: should happen in quicktime module, but it currently doesn't have access * to color management's internals */ ibuf->rect_colorspace = colormanage_colorspace_get_named(anim->colorspace); } anim->curposition = position; } break; #endif #ifdef WITH_FFMPEG case ANIM_FFMPEG: ibuf = ffmpeg_fetchibuf(anim, position, tc); if (ibuf) anim->curposition = position; filter_y = 0; /* done internally */ break; #endif #ifdef WITH_REDCODE case ANIM_REDCODE: ibuf = redcode_fetchibuf(anim, position); if (ibuf) anim->curposition = position; break; #endif } if (ibuf) { if (filter_y) IMB_filtery(ibuf); BLI_snprintf(ibuf->name, sizeof(ibuf->name), "%s.%04d", anim->name, anim->curposition + 1); } return(ibuf); }
static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) { ImBuf * ibuf; int frameFinished; AVPacket packet; int64_t pts_to_search = 0; int pos_found = 1; int filter_y = 0; int seek_by_bytes= 0; int preseek_count = 0; if (anim == 0) return (0); ibuf = IMB_allocImBuf(anim->x, anim->y, 32, IB_rect); avpicture_fill((AVPicture*) anim->pFrameRGB, (unsigned char*) ibuf->rect, PIX_FMT_RGBA, anim->x, anim->y); if (position != anim->curposition + 1) { if (position > anim->curposition + 1 && anim->preseek && position - (anim->curposition + 1) < anim->preseek) { while(av_read_frame(anim->pFormatCtx, &packet)>=0) { if (packet.stream_index == anim->videoStream) { avcodec_decode_video2( anim->pCodecCtx, anim->pFrame, &frameFinished, &packet); if (frameFinished) { anim->curposition++; } } av_free_packet(&packet); if (position == anim->curposition+1) { break; } } } } /* disable seek_by_bytes for now, since bitrates are guessed wrong! also: MPEG2TS-seeking was fixed in later versions of ffmpeg, so problem is somewhat fixed by now (until we add correct timecode management code...) */ #if 0 seek_by_bytes = !!(anim->pFormatCtx->iformat->flags & AVFMT_TS_DISCONT); #else seek_by_bytes = FALSE; #endif if (position != anim->curposition + 1) { double frame_rate = av_q2d(anim->pFormatCtx->streams[anim->videoStream] ->r_frame_rate); double pts_time_base = av_q2d(anim->pFormatCtx->streams[anim->videoStream]->time_base); long long pos; long long st_time = anim->pFormatCtx->start_time; int ret; if (seek_by_bytes) { pos = position - anim->preseek; if (pos < 0) { pos = 0; } preseek_count = position - pos; pos *= anim->pFormatCtx->bit_rate / frame_rate; pos /= 8; } else { pos = (long long) (position - anim->preseek) * AV_TIME_BASE / frame_rate; if (pos < 0) { pos = 0; } if (st_time != AV_NOPTS_VALUE) { pos += st_time; } } ret = av_seek_frame(anim->pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD | ( seek_by_bytes ? AVSEEK_FLAG_ANY | AVSEEK_FLAG_BYTE : 0)); if (ret < 0) { fprintf(stderr, "error while seeking: %d\n", ret); } pts_to_search = (long long) (((double) position) / pts_time_base / frame_rate); if (st_time != AV_NOPTS_VALUE) { pts_to_search += st_time / pts_time_base/ AV_TIME_BASE; } pos_found = 0; avcodec_flush_buffers(anim->pCodecCtx); } while(av_read_frame(anim->pFormatCtx, &packet)>=0) { if(packet.stream_index == anim->videoStream) { avcodec_decode_video2(anim->pCodecCtx, anim->pFrame, &frameFinished, &packet); if (seek_by_bytes && preseek_count > 0) { preseek_count--; } if (frameFinished && !pos_found) { if (seek_by_bytes) { if (!preseek_count) { pos_found = 1; anim->curposition = position; } } else { if (packet.dts >= pts_to_search) { pos_found = 1; anim->curposition = position; } } } if(frameFinished && pos_found == 1) { ffmpeg_postprocess(anim, ibuf, &filter_y); av_free_packet(&packet); break; } } av_free_packet(&packet); } if (filter_y && ibuf) { IMB_filtery(ibuf); } ibuf->profile = IB_PROFILE_SRGB; return(ibuf); }
static void ffmpeg_postprocess(struct anim * anim) { AVFrame * input = anim->pFrame; ImBuf * ibuf = anim->last_frame; int filter_y = 0; ibuf->profile = IB_PROFILE_SRGB; /* This means the data wasnt read properly, this check stops crashing */ if (input->data[0]==0 && input->data[1]==0 && input->data[2]==0 && input->data[3]==0){ fprintf(stderr, "ffmpeg_fetchibuf: " "data not read properly...\n"); return; } if (anim->ib_flags & IB_animdeinterlace) { if (avpicture_deinterlace( (AVPicture*) anim->pFrameDeinterlaced, (const AVPicture*) anim->pFrame, anim->pCodecCtx->pix_fmt, anim->pCodecCtx->width, anim->pCodecCtx->height) < 0) { filter_y = TRUE; } else { input = anim->pFrameDeinterlaced; } } avpicture_fill((AVPicture*) anim->pFrameRGB, (unsigned char*) ibuf->rect, PIX_FMT_RGBA, anim->x, anim->y); if (ENDIAN_ORDER == B_ENDIAN) { int * dstStride = anim->pFrameRGB->linesize; uint8_t** dst = anim->pFrameRGB->data; int dstStride2[4] = { dstStride[0], 0, 0, 0 }; uint8_t* dst2[4] = { dst[0], 0, 0, 0 }; int x,y,h,w; unsigned char* bottom; unsigned char* top; sws_scale(anim->img_convert_ctx, (const uint8_t * const *)input->data, input->linesize, 0, anim->pCodecCtx->height, dst2, dstStride2); /* workaround: sws_scale bug sets alpha = 0 and compensate for altivec-bugs and flipy... */ bottom = (unsigned char*) ibuf->rect; top = bottom + ibuf->x * (ibuf->y-1) * 4; h = (ibuf->y + 1) / 2; w = ibuf->x; for (y = 0; y < h; y++) { unsigned char tmp[4]; unsigned int * tmp_l = (unsigned int*) tmp; tmp[3] = 0xff; for (x = 0; x < w; x++) { tmp[0] = bottom[0]; tmp[1] = bottom[1]; tmp[2] = bottom[2]; bottom[0] = top[0]; bottom[1] = top[1]; bottom[2] = top[2]; bottom[3] = 0xff; *(unsigned int*) top = *tmp_l; bottom +=4; top += 4; } top -= 8 * w; } } else { int * dstStride = anim->pFrameRGB->linesize; uint8_t** dst = anim->pFrameRGB->data; int dstStride2[4] = { -dstStride[0], 0, 0, 0 }; uint8_t* dst2[4] = { dst[0] + (anim->y - 1)*dstStride[0], 0, 0, 0 }; int i; unsigned char* r; sws_scale(anim->img_convert_ctx, (const uint8_t * const *)input->data, input->linesize, 0, anim->pCodecCtx->height, dst2, dstStride2); r = (unsigned char*) ibuf->rect; /* workaround sws_scale bug: older version of sws_scale set alpha = 0... */ if (r[3] == 0) { for (i = 0; i < ibuf->x * ibuf->y; i++) { r[3] = 0xff; r += 4; } } } if (filter_y) { IMB_filtery(ibuf); } }
struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) { struct ImBuf * ibuf = NULL; char head[256], tail[256]; unsigned short digits; int pic; int filter_y; if (anim == NULL) return(NULL); filter_y = (anim->ib_flags & IB_animdeinterlace); if (anim->curtype == 0) { ibuf = anim_getnew(anim); if (ibuf == NULL) { return(NULL); } IMB_freeImBuf(ibuf); /* ???? */ ibuf= NULL; } if (position < 0) return(NULL); if (position >= anim->duration) return(NULL); switch(anim->curtype) { case ANIM_SEQUENCE: pic = an_stringdec(anim->first, head, tail, &digits); pic += position; an_stringenc(anim->name, head, tail, digits, pic); ibuf = IMB_loadiffname(anim->name, IB_rect); if (ibuf) { anim->curposition = position; } break; case ANIM_MOVIE: ibuf = movie_fetchibuf(anim, position); if (ibuf) { anim->curposition = position; IMB_convert_rgba_to_abgr(ibuf); ibuf->profile = IB_PROFILE_SRGB; } break; case ANIM_AVI: ibuf = avi_fetchibuf(anim, position); if (ibuf) anim->curposition = position; break; #ifdef WITH_QUICKTIME case ANIM_QTIME: ibuf = qtime_fetchibuf(anim, position); if (ibuf) anim->curposition = position; break; #endif #ifdef WITH_FFMPEG case ANIM_FFMPEG: ibuf = ffmpeg_fetchibuf(anim, position); if (ibuf) anim->curposition = position; filter_y = 0; /* done internally */ break; #endif #ifdef WITH_REDCODE case ANIM_REDCODE: ibuf = redcode_fetchibuf(anim, position); if (ibuf) anim->curposition = position; break; #endif } if (ibuf) { if (filter_y) IMB_filtery(ibuf); sprintf(ibuf->name, "%s.%04d", anim->name, anim->curposition + 1); } return(ibuf); }