[PATCH 1/7] lavc/libopenjpegdec: support interlaced layout
Fixes tickets #1102. Interlaced layout is supported thought use of codec extradata: avctx->extradata[0] enables interlaced layout, avctx->extradata[1] stores field order. --- libavcodec/libopenjpegdec.c | 99 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 19 deletions(-) diff --git a/libavcodec/libopenjpegdec.c b/libavcodec/libopenjpegdec.c index f8b6165..4ea0489 100644 --- a/libavcodec/libopenjpegdec.c +++ b/libavcodec/libopenjpegdec.c @@ -68,6 +68,12 @@ typedef struct { AVClass *class; opj_dparameters_t dec_params; int lowqual; + AVFrame* picture; + uint64_t curpict; + int separate_fields; + int field_order; + int top_field_coded_first; + int width, height; } LibOpenJPEGContext; static inline int libopenjpeg_matches_pix_fmt(const opj_image_t *image, enum AVPixelFormat pix_fmt) @@ -148,12 +154,13 @@ static inline int libopenjpeg_ispacked(enum AVPixelFormat pix_fmt) return 1; } -static inline void libopenjpeg_copy_to_packed8(AVFrame *picture, opj_image_t *image) { +static inline void libopenjpeg_copy_to_packed8(AVFrame *picture, opj_image_t *image, int separate_fields, int field_pos) { uint8_t *img_ptr; - int index, x, y, c; + int index, x, y, c, line; for (y = 0; y < picture->height; y++) { index = y*picture->width; - img_ptr = picture->data[0] + y*picture->linesize[0]; + line = separate_fields * (field_pos + y) + y; + img_ptr = picture->data[0] + line*picture->linesize[0]; for (x = 0; x < picture->width; x++, index++) { for (c = 0; c < image->numcomps; c++) { *img_ptr++ = image->comps[c].data[index]; @@ -162,16 +169,17 @@ static inline void libopenjpeg_copy_to_packed8(AVFrame *picture, opj_image_t *im } } -static inline void libopenjpeg_copy_to_packed16(AVFrame *picture, opj_image_t *image) { +static inline void libopenjpeg_copy_to_packed16(AVFrame *picture, opj_image_t *image, int separate_fields, int field_pos) { uint16_t *img_ptr; - int index, x, y, c; + int index, x, y, c, line; int adjust[4]; for (x = 0; x < image->numcomps; x++) adjust[x] = FFMAX(FFMIN(16 - image->comps[x].prec, 8), 0); for (y = 0; y < picture->height; y++) { index = y*picture->width; - img_ptr = (uint16_t*) (picture->data[0] + y*picture->linesize[0]); + line = separate_fields * (field_pos + y) + y; + img_ptr = (uint16_t*) (picture->data[0] + line*picture->linesize[0]); for (x = 0; x < picture->width; x++, index++) { for (c = 0; c < image->numcomps; c++) { *img_ptr++ = image->comps[c].data[index] << adjust[c]; @@ -180,7 +188,7 @@ static inline void libopenjpeg_copy_to_packed16(AVFrame *picture, opj_image_t *i } } -static inline void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image) { +static inline void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image, int separate_fields, int field_pos) { int *comp_data; uint8_t *img_ptr; int index, x, y; @@ -188,7 +196,8 @@ static inline void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image) { for (index = 0; index < image->numcomps; index++) { comp_data = image->comps[index].data; for (y = 0; y < image->comps[index].h; y++) { - img_ptr = picture->data[index] + y * picture->linesize[index]; + int line = separate_fields * (field_pos + y) + y; + img_ptr = picture->data[index] + line * picture->linesize[index]; for (x = 0; x < image->comps[index].w; x++) { *img_ptr = (uint8_t) *comp_data; img_ptr++; @@ -198,14 +207,15 @@ static inline void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image) { } } -static inline void libopenjpeg_copyto16(AVFrame *picture, opj_image_t *image) { +static inline void libopenjpeg_copyto16(AVFrame *picture, opj_image_t *image, int separate_fields, int field_pos) { int *comp_data; uint16_t *img_ptr; int index, x, y; for (index = 0; index < image->numcomps; index++) { comp_data = image->comps[index].data; for (y = 0; y < image->comps[index].h; y++) { - img_ptr = (uint16_t*) (picture->data[index] + y * picture->linesize[index]); + int line = separate_fields * (field_pos + y) + y; + img_ptr = (uint16_t*) (picture->data[index] + line * picture->linesize[index]); for (x = 0; x < image->comps[index].w; x++) { *img_ptr = *comp_data; img_ptr++; @@ -219,10 +229,27 @@ static av_cold int libopenjpeg_decode_init(AVCodecContext *avctx) { LibOpenJPEGContext *ctx = avctx->priv_data; + if (avctx->extradata_size > 2) { + ctx->picture = av_frame_alloc(); + ctx->separate_fields = avctx->extradata[0]; + if (ctx->separate_fields) { + avctx->field_order = ctx->field_order = avctx->extradata[1]; + ctx->top_field_coded_first = (ctx->field_order == AV_FIELD_TT || + ctx->field_order == AV_FIELD_TB); + } + } + opj_set_default_decoder_parameters(&ctx->dec_params); return 0; } +static av_cold int libopenjpeg_decode_uninit(AVCodecContext *avctx) +{ + LibOpenJPEGContext *ctx = avctx->priv_data; + av_frame_free(&ctx->picture); + return 0; +} + static int libopenjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) @@ -239,9 +266,22 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, int width, height, ret = -1; int pixel_size = 0; int ispacked = 0; - int i; + int realloc_il_buffer = 0; + int i, field_pos, field_nb; *got_frame = 0; + if (ctx->separate_fields) { + picture = ctx->picture; + frame.f = picture; + } + + field_nb = ctx->curpict % 2; + field_pos = field_nb ^ !ctx->top_field_coded_first; + + if (ctx->separate_fields && avctx->thread_count > 1) { + av_log(avctx, AV_LOG_ERROR, "Separate fields layout does not support threading. Please specify -threads 1 before input.\n"); + return AVERROR(EINVAL); + } // Check if input is a raw jpeg2k codestream or in jp2 wrapping if ((AV_RB32(buf) == 12) && @@ -287,12 +327,21 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, width = image->x1 - image->x0; height = image->y1 - image->y0; + if (ctx->separate_fields) + height *= 2; + if (av_image_check_size(width, height, 0, avctx) < 0) { av_log(avctx, AV_LOG_ERROR, "%dx%d dimension invalid.\n", width, height); goto done; } + if (ctx->width != width || ctx->height != height) { + ctx->width = width; + ctx->height = height; + realloc_il_buffer = 1; + } + avcodec_set_dimensions(avctx, width, height); if (avctx->pix_fmt != AV_PIX_FMT_NONE) @@ -310,8 +359,13 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, if (image->comps[i].prec > avctx->bits_per_raw_sample) avctx->bits_per_raw_sample = image->comps[i].prec; - if (ff_thread_get_buffer(avctx, &frame, 0) < 0) - goto done; + if (ctx->separate_fields && realloc_il_buffer && picture->data[0]) + av_frame_unref(picture); + + if (!ctx->separate_fields || + (ctx->separate_fields && (!ctx->curpict || realloc_il_buffer))) + if (ff_thread_get_buffer(avctx, &frame, 0) < 0) + goto done; ctx->dec_params.cp_limit_decoding = NO_LIMITATION; ctx->dec_params.cp_reduce = avctx->lowres; @@ -341,28 +395,28 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, switch (pixel_size) { case 1: if (ispacked) { - libopenjpeg_copy_to_packed8(picture, image); + libopenjpeg_copy_to_packed8(picture, image, ctx->separate_fields, field_pos); } else { - libopenjpeg_copyto8(picture, image); + libopenjpeg_copyto8(picture, image, ctx->separate_fields, field_pos); } break; case 2: if (ispacked) { - libopenjpeg_copy_to_packed8(picture, image); + libopenjpeg_copy_to_packed8(picture, image, ctx->separate_fields, field_pos); } else { - libopenjpeg_copyto16(picture, image); + libopenjpeg_copyto16(picture, image, ctx->separate_fields, field_pos); } break; case 3: case 4: if (ispacked) { - libopenjpeg_copy_to_packed8(picture, image); + libopenjpeg_copy_to_packed8(picture, image, ctx->separate_fields, field_pos); } break; case 6: case 8: if (ispacked) { - libopenjpeg_copy_to_packed16(picture, image); + libopenjpeg_copy_to_packed16(picture, image, ctx->separate_fields, field_pos); } break; default: @@ -373,7 +427,13 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, *got_frame = 1; ret = buf_size; + if (ctx->separate_fields) + if (field_nb) + av_frame_ref(data, ctx->picture); + else + *got_frame = 0; done: + ctx->curpict++; opj_image_destroy(image); opj_destroy_decompress(dec); return ret; @@ -401,6 +461,7 @@ AVCodec ff_libopenjpeg_decoder = { .priv_data_size = sizeof(LibOpenJPEGContext), .init = libopenjpeg_decode_init, .decode = libopenjpeg_decode_frame, + .close = libopenjpeg_decode_uninit, .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS, .max_lowres = 31, .long_name = NULL_IF_CONFIG_SMALL("OpenJPEG JPEG 2000"), -- 1.8.2
According to S377M, segmented frame layout is identical to separate field layout except that the two fields are taken from a single scan of the incoming image, ie: they are coincident in time. Thus the resulting frame is progressive. --- libavformat/mxfdec.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 4580e1b..5244e47 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1526,10 +1526,6 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->width = descriptor->width; st->codec->height = descriptor->height; /* Field height, not frame height */ switch (descriptor->frame_layout) { - case SegmentedFrame: - /* This one is a weird layout I don't fully understand. */ - av_log(mxf->fc, AV_LOG_INFO, "SegmentedFrame layout isn't currently supported\n"); - break; case FullFrame: st->codec->field_order = AV_FIELD_PROGRESSIVE; break; @@ -1541,6 +1537,8 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) It's also for compatibility with the old behavior. */ case MixedFields: break; + case SegmentedFrame: + st->codec->field_order = AV_FIELD_PROGRESSIVE; case SeparateFields: st->codec->height *= 2; /* Turn field height into frame height. */ break; -- 1.8.2
--- libavformat/mxfdec.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 5244e47..8455790 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1545,7 +1545,27 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) default: av_log(mxf->fc, AV_LOG_INFO, "Unknown frame layout type: %d\n", descriptor->frame_layout); } - if (st->codec->codec_id == AV_CODEC_ID_RAWVIDEO) { + switch (st->codec->codec_id) { + case AV_CODEC_ID_JPEG2000: + if (descriptor->frame_layout == SegmentedFrame || + descriptor->frame_layout == SeparateFields) { + st->codec->extradata_size = 2; + st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); + if (!st->codec->extradata) + return AVERROR(ENOMEM); + st->codec->extradata[0] = 1; + if (descriptor->field_dominance == 1) + st->codec->extradata[1] = AV_FIELD_TT; + else if (descriptor->field_dominance == 2) + st->codec->extradata[1] = AV_FIELD_BB; + else { + av_log(mxf->fc, AV_LOG_INFO, + "Invalid field dominance value: %d, defaulting to TFF\n", descriptor->field_dominance); + st->codec->extradata[1] = AV_FIELD_TT; + } + } + break; + case AV_CODEC_ID_RAWVIDEO: st->codec->pix_fmt = descriptor->pix_fmt; if (st->codec->pix_fmt == AV_PIX_FMT_NONE) { pix_fmt_ul = mxf_get_codec_ul(ff_mxf_pixel_format_uls, @@ -1561,6 +1581,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) } } } + break; } st->need_parsing = AVSTREAM_PARSE_HEADERS; } else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { -- 1.8.2
Matthieu Bouron <matthieu.bouron <at> gmail.com> writes:
+ if (descriptor->frame_layout == SegmentedFrame || + descriptor->frame_layout == SeparateFields) { + st->codec->extradata_size = 2;
Shouldn't this be stream metadata? Carl Eugen
On Thu, Mar 28, 2013 at 03:00:53PM +0000, Carl Eugen Hoyos wrote:
Matthieu Bouron <matthieu.bouron <at> gmail.com> writes:
+ if (descriptor->frame_layout == SegmentedFrame || + descriptor->frame_layout == SeparateFields) { + st->codec->extradata_size = 2;
Shouldn't this be stream metadata?
Since this information is directly used by the decoder, i thought it was a good option to use avctx->extradata. Is stream metadata accessible from the decoder ? Matthieu
--- libavformat/mxfdec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 8455790..190d205 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -941,6 +941,7 @@ static const MXFCodecUL mxf_intra_only_essence_container_uls[] = { /* intra-only PictureEssenceCoding ULs, where no corresponding EC UL exists */ static const MXFCodecUL mxf_intra_only_picture_essence_coding_uls[] = { { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x01,0x32,0x00,0x00 }, 14, AV_CODEC_ID_H264 }, /* H.264/MPEG-4 AVC Intra Profiles */ + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x07,0x04,0x01,0x02,0x02,0x03,0x01,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, /* JPEG2000 Codestream */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; -- 1.8.2
On Thu, Mar 28, 2013 at 03:41:48PM +0100, Matthieu Bouron wrote:
--- libavformat/mxfdec.c | 1 + 1 file changed, 1 insertion(+)
applied thanks -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB Those who are best at talking, realize last or never when they are wrong.
Packet ptses correspond to field number - 1. This plus dividing by a factor of 2 the stream time base will output correct ptses for decoded frames since we need 2 packets for one decoded frame. --- libavformat/mxfdec.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 190d205..7b7ac90 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -135,6 +135,8 @@ typedef struct { int intra_only; uint64_t sample_count; int64_t original_duration; ///< duration before multiplying st->duration by SampleRate/EditRate + int64_t field_count; + int frame_layout; } MXFTrack; typedef struct { @@ -1526,6 +1528,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) st->codec->codec_id = container_ul->id; st->codec->width = descriptor->width; st->codec->height = descriptor->height; /* Field height, not frame height */ + source_track->frame_layout = descriptor->frame_layout; switch (descriptor->frame_layout) { case FullFrame: st->codec->field_order = AV_FIELD_PROGRESSIVE; @@ -2173,17 +2176,24 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) pkt->pos = klv.offset; codec = s->streams[index]->codec; - if (codec->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) { - /* mxf->current_edit_unit good - see if we have an index table to derive timestamps from */ - MXFIndexTable *t = &mxf->index_tables[0]; - - if (mxf->nb_index_tables >= 1 && mxf->current_edit_unit < t->nb_ptses) { - pkt->dts = mxf->current_edit_unit + t->first_dts; - pkt->pts = t->ptses[mxf->current_edit_unit]; - } else if (track->intra_only) { - /* intra-only -> PTS = EditUnit. - * let utils.c figure out DTS since it can be < PTS if low_delay = 0 (Sony IMX30) */ - pkt->pts = mxf->current_edit_unit; + if (codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (codec->codec_id == AV_CODEC_ID_JPEG2000 && + (track->frame_layout == SeparateFields || + track->frame_layout == SegmentedFrame)) { + pkt->pts = track->field_count - 1; + track->field_count++; + } else if (next_ofs >= 0) { + /* mxf->current_edit_unit good - see if we have an index table to derive timestamps from */ + MXFIndexTable *t = &mxf->index_tables[0]; + + if (mxf->nb_index_tables >= 1 && mxf->current_edit_unit < t->nb_ptses) { + pkt->dts = mxf->current_edit_unit + t->first_dts; + pkt->pts = t->ptses[mxf->current_edit_unit]; + } else if (track->intra_only) { + /* intra-only -> PTS = EditUnit. + * let utils.c figure out DTS since it can be < PTS if low_delay = 0 (Sony IMX30) */ + pkt->pts = mxf->current_edit_unit; + } } } else if (codec->codec_type == AVMEDIA_TYPE_AUDIO) { int ret = mxf_set_audio_pts(mxf, codec, pkt); @@ -2208,6 +2218,7 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) int ret, size; int64_t ret64, pos, next_pos; AVStream *st; + MXFTrack *track; MXFIndexTable *t; int edit_units; @@ -2248,7 +2259,13 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->stream_index = 0; - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && t->ptses && + track = st->priv_data; + if (st->codec->codec_id == AV_CODEC_ID_JPEG2000 && + (track->frame_layout == SeparateFields || + track->frame_layout == SegmentedFrame)) { + pkt->pts = track->field_count - 1; + track->field_count++; + } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && t->ptses && mxf->current_edit_unit >= 0 && mxf->current_edit_unit < t->nb_ptses) { pkt->dts = mxf->current_edit_unit + t->first_dts; pkt->pts = t->ptses[mxf->current_edit_unit]; -- 1.8.2
Since two packets are required to decoded a frame, we need to divide by a factor of 2 the stream time base so output ptses are correct. --- libavformat/mxfdec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 7b7ac90..171d32e 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1553,6 +1553,8 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) case AV_CODEC_ID_JPEG2000: if (descriptor->frame_layout == SegmentedFrame || descriptor->frame_layout == SeparateFields) { + st->codec->time_base = st->time_base; + st->time_base = (AVRational) { st->time_base.num, st->time_base.den * 2}; st->codec->extradata_size = 2; st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) -- 1.8.2
Interpret sample rate as field rate for j2k codec with separate fields or segmented frame layout. This option is required to obtain a correct frame rate since S422M specifies that the track sample rate could either be the frame rate or the field rate for separate field layout. For segmented frame layout, the track sample rate is supposed to be the frame rate however some sample seems to use it as the field rate. --- libavformat/mxfdec.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 171d32e..dddebf4 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -48,6 +48,7 @@ #include "libavutil/aes.h" #include "libavutil/avassert.h" #include "libavutil/mathematics.h" +#include "libavutil/opt.h" #include "libavcodec/bytestream.h" #include "libavutil/timecode.h" #include "avformat.h" @@ -206,6 +207,7 @@ typedef struct { } MXFIndexTable; typedef struct { + const AVClass *class; MXFPartition *partitions; unsigned partitions_count; MXFOP op; @@ -229,6 +231,7 @@ typedef struct { int nb_index_tables; MXFIndexTable *index_tables; int edit_units_per_packet; ///< how many edit units to read at a time (PCM, OPAtom) + int field_rate; } MXFContext; enum MXFWrappingScheme { @@ -1553,8 +1556,12 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) case AV_CODEC_ID_JPEG2000: if (descriptor->frame_layout == SegmentedFrame || descriptor->frame_layout == SeparateFields) { - st->codec->time_base = st->time_base; - st->time_base = (AVRational) { st->time_base.num, st->time_base.den * 2}; + if (mxf->field_rate) { + st->codec->time_base = (AVRational) { st->time_base.num, st->time_base.den / 2 }; + } else { + st->codec->time_base = st->time_base; + st->time_base = (AVRational) { st->time_base.num, st->time_base.den * 2}; + } st->codec->extradata_size = 2; st->codec->extradata = av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE); if (!st->codec->extradata) @@ -2419,6 +2426,22 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti return 0; } + +#define OFFSET(x) offsetof(MXFContext, x) +#define DEC AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + { "field_rate", "Interpret sample rate as field rate.", + OFFSET(field_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC }, + { NULL }, +}; + +static const AVClass mxf_demuxer_class = { + .class_name = "MXF demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVInputFormat ff_mxf_demuxer = { .name = "mxf", .long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"), @@ -2428,4 +2451,5 @@ AVInputFormat ff_mxf_demuxer = { .read_packet = mxf_read_packet, .read_close = mxf_read_close, .read_seek = mxf_read_seek, + .priv_class = &mxf_demuxer_class, }; -- 1.8.2
On Thu, Mar 28, 2013 at 03:41:51PM +0100, Matthieu Bouron wrote:
Interpret sample rate as field rate for j2k codec with separate fields or segmented frame layout.
This option is required to obtain a correct frame rate since S422M specifies that the track sample rate could either be the frame rate or the field rate for separate field layout.
For segmented frame layout, the track sample rate is supposed to be the frame rate however some sample seems to use it as the field rate.
are you sure theres no way to distingish them automatically ? file duration fields? encoder name? muxer name? ... [...] -- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB The greatest way to live with honor in this world is to be what we pretend to be. -- Socrates
On Thu, Mar 28, 2013 at 04:37:10PM +0100, Michael Niedermayer wrote:
On Thu, Mar 28, 2013 at 03:41:51PM +0100, Matthieu Bouron wrote:
Interpret sample rate as field rate for j2k codec with separate fields or segmented frame layout.
This option is required to obtain a correct frame rate since S422M specifies that the track sample rate could either be the frame rate or the field rate for separate field layout.
For segmented frame layout, the track sample rate is supposed to be the frame rate however some sample seems to use it as the field rate.
are you sure theres no way to distingish them automatically ? file duration fields? encoder name? muxer name? ...
AFAIK there is no mandatory information that can be used to interpret correctly the sample rate. Based on the few samples i have: - the one provided on ffmpeg trac (ntsc2.mxf): sample rate is frame rate, - the files issued by SAMMA systems: sample rate is field rate, - the files issued by Canopus Co. systems: sample rate is field rate. Maybe i could use the application_supplier_name from the mxf identification item to set a default behaviour ? For reference, page 5 of http://www.digitizationguidelines.gov/guidelines/FADGI_MXF_ASAP_Issues_20110... Matthieu
On Thu, Mar 28, 2013 at 05:15:28PM +0100, Matthieu Bouron wrote:
On Thu, Mar 28, 2013 at 04:37:10PM +0100, Michael Niedermayer wrote:
On Thu, Mar 28, 2013 at 03:41:51PM +0100, Matthieu Bouron wrote:
Interpret sample rate as field rate for j2k codec with separate fields or segmented frame layout.
This option is required to obtain a correct frame rate since S422M specifies that the track sample rate could either be the frame rate or the field rate for separate field layout.
For segmented frame layout, the track sample rate is supposed to be the frame rate however some sample seems to use it as the field rate.
are you sure theres no way to distingish them automatically ? file duration fields? encoder name? muxer name? ...
AFAIK there is no mandatory information that can be used to interpret correctly the sample rate.
Based on the few samples i have: - the one provided on ffmpeg trac (ntsc2.mxf): sample rate is frame rate, - the files issued by SAMMA systems: sample rate is field rate, - the files issued by Canopus Co. systems: sample rate is field rate.
Maybe i could use the application_supplier_name from the mxf identification item to set a default behaviour ?
yes, its maybe a bit trial and error but IMHO its worth a try to set it automatically
For reference, page 5 of http://www.digitizationguidelines.gov/guidelines/FADGI_MXF_ASAP_Issues_20110...
Matthieu _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
-- Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB The educated differ from the uneducated as much as the living from the dead. -- Aristotle
On Thu, 2013-03-28 at 17:33 +0100, Michael Niedermayer wrote:
On Thu, Mar 28, 2013 at 05:15:28PM +0100, Matthieu Bouron wrote:
On Thu, Mar 28, 2013 at 04:37:10PM +0100, Michael Niedermayer wrote:
On Thu, Mar 28, 2013 at 03:41:51PM +0100, Matthieu Bouron wrote:
Interpret sample rate as field rate for j2k codec with separate fields or segmented frame layout.
This option is required to obtain a correct frame rate since S422M specifies that the track sample rate could either be the frame rate or the field rate for separate field layout.
For segmented frame layout, the track sample rate is supposed to be the frame rate however some sample seems to use it as the field rate.
are you sure theres no way to distingish them automatically ? file duration fields? encoder name? muxer name? ...
AFAIK there is no mandatory information that can be used to interpret correctly the sample rate.
Based on the few samples i have: - the one provided on ffmpeg trac (ntsc2.mxf): sample rate is frame rate, - the files issued by SAMMA systems: sample rate is field rate, - the files issued by Canopus Co. systems: sample rate is field rate.
Maybe i could use the application_supplier_name from the mxf identification item to set a default behaviour ?
yes, its maybe a bit trial and error but IMHO its worth a try to set it automatically
I agree. We're already handling a few bad files in ways similar to this, and it's generally how the industry handles MXF interoperability as well. Yes, it's a complete mess. /Tomas
On Thu, Mar 28, 2013 at 03:41:45PM +0100, Matthieu Bouron wrote:
Fixes tickets #1102.
Interlaced layout is supported thought use of codec extradata: avctx->extradata[0] enables interlaced layout, avctx->extradata[1] stores field order. --- libavcodec/libopenjpegdec.c | 99 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 80 insertions(+), 19 deletions(-)
diff --git a/libavcodec/libopenjpegdec.c b/libavcodec/libopenjpegdec.c index f8b6165..4ea0489 100644 --- a/libavcodec/libopenjpegdec.c +++ b/libavcodec/libopenjpegdec.c @@ -68,6 +68,12 @@ typedef struct { AVClass *class; opj_dparameters_t dec_params; int lowqual; + AVFrame* picture; + uint64_t curpict; + int separate_fields; + int field_order; + int top_field_coded_first; + int width, height; } LibOpenJPEGContext;
static inline int libopenjpeg_matches_pix_fmt(const opj_image_t *image, enum AVPixelFormat pix_fmt) @@ -148,12 +154,13 @@ static inline int libopenjpeg_ispacked(enum AVPixelFormat pix_fmt) return 1; }
-static inline void libopenjpeg_copy_to_packed8(AVFrame *picture, opj_image_t *image) { +static inline void libopenjpeg_copy_to_packed8(AVFrame *picture, opj_image_t *image, int separate_fields, int field_pos) { uint8_t *img_ptr; - int index, x, y, c; + int index, x, y, c, line; for (y = 0; y < picture->height; y++) { index = y*picture->width; - img_ptr = picture->data[0] + y*picture->linesize[0]; + line = separate_fields * (field_pos + y) + y; + img_ptr = picture->data[0] + line*picture->linesize[0]; for (x = 0; x < picture->width; x++, index++) { for (c = 0; c < image->numcomps; c++) { *img_ptr++ = image->comps[c].data[index]; @@ -162,16 +169,17 @@ static inline void libopenjpeg_copy_to_packed8(AVFrame *picture, opj_image_t *im } }
-static inline void libopenjpeg_copy_to_packed16(AVFrame *picture, opj_image_t *image) { +static inline void libopenjpeg_copy_to_packed16(AVFrame *picture, opj_image_t *image, int separate_fields, int field_pos) { uint16_t *img_ptr; - int index, x, y, c; + int index, x, y, c, line; int adjust[4]; for (x = 0; x < image->numcomps; x++) adjust[x] = FFMAX(FFMIN(16 - image->comps[x].prec, 8), 0);
for (y = 0; y < picture->height; y++) { index = y*picture->width; - img_ptr = (uint16_t*) (picture->data[0] + y*picture->linesize[0]); + line = separate_fields * (field_pos + y) + y; + img_ptr = (uint16_t*) (picture->data[0] + line*picture->linesize[0]); for (x = 0; x < picture->width; x++, index++) { for (c = 0; c < image->numcomps; c++) { *img_ptr++ = image->comps[c].data[index] << adjust[c]; @@ -180,7 +188,7 @@ static inline void libopenjpeg_copy_to_packed16(AVFrame *picture, opj_image_t *i } }
-static inline void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image) { +static inline void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image, int separate_fields, int field_pos) { int *comp_data; uint8_t *img_ptr; int index, x, y; @@ -188,7 +196,8 @@ static inline void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image) { for (index = 0; index < image->numcomps; index++) { comp_data = image->comps[index].data; for (y = 0; y < image->comps[index].h; y++) { - img_ptr = picture->data[index] + y * picture->linesize[index]; + int line = separate_fields * (field_pos + y) + y; + img_ptr = picture->data[index] + line * picture->linesize[index]; for (x = 0; x < image->comps[index].w; x++) { *img_ptr = (uint8_t) *comp_data; img_ptr++; @@ -198,14 +207,15 @@ static inline void libopenjpeg_copyto8(AVFrame *picture, opj_image_t *image) { } }
-static inline void libopenjpeg_copyto16(AVFrame *picture, opj_image_t *image) { +static inline void libopenjpeg_copyto16(AVFrame *picture, opj_image_t *image, int separate_fields, int field_pos) { int *comp_data; uint16_t *img_ptr; int index, x, y; for (index = 0; index < image->numcomps; index++) { comp_data = image->comps[index].data; for (y = 0; y < image->comps[index].h; y++) { - img_ptr = (uint16_t*) (picture->data[index] + y * picture->linesize[index]); + int line = separate_fields * (field_pos + y) + y; + img_ptr = (uint16_t*) (picture->data[index] + line * picture->linesize[index]); for (x = 0; x < image->comps[index].w; x++) { *img_ptr = *comp_data; img_ptr++; @@ -219,10 +229,27 @@ static av_cold int libopenjpeg_decode_init(AVCodecContext *avctx) { LibOpenJPEGContext *ctx = avctx->priv_data;
+ if (avctx->extradata_size > 2) { + ctx->picture = av_frame_alloc(); + ctx->separate_fields = avctx->extradata[0]; + if (ctx->separate_fields) { + avctx->field_order = ctx->field_order = avctx->extradata[1]; + ctx->top_field_coded_first = (ctx->field_order == AV_FIELD_TT || + ctx->field_order == AV_FIELD_TB); + } + } + opj_set_default_decoder_parameters(&ctx->dec_params); return 0; }
+static av_cold int libopenjpeg_decode_uninit(AVCodecContext *avctx) +{ + LibOpenJPEGContext *ctx = avctx->priv_data; + av_frame_free(&ctx->picture); + return 0; +} + static int libopenjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) @@ -239,9 +266,22 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, int width, height, ret = -1; int pixel_size = 0; int ispacked = 0; - int i; + int realloc_il_buffer = 0; + int i, field_pos, field_nb;
*got_frame = 0; + if (ctx->separate_fields) { + picture = ctx->picture; + frame.f = picture; + } + + field_nb = ctx->curpict % 2; + field_pos = field_nb ^ !ctx->top_field_coded_first; + + if (ctx->separate_fields && avctx->thread_count > 1) { + av_log(avctx, AV_LOG_ERROR, "Separate fields layout does not support threading. Please specify -threads 1 before input.\n"); + return AVERROR(EINVAL); + }
// Check if input is a raw jpeg2k codestream or in jp2 wrapping if ((AV_RB32(buf) == 12) && @@ -287,12 +327,21 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, width = image->x1 - image->x0; height = image->y1 - image->y0;
+ if (ctx->separate_fields) + height *= 2; + if (av_image_check_size(width, height, 0, avctx) < 0) { av_log(avctx, AV_LOG_ERROR, "%dx%d dimension invalid.\n", width, height); goto done; }
+ if (ctx->width != width || ctx->height != height) { + ctx->width = width; + ctx->height = height; + realloc_il_buffer = 1; + } + avcodec_set_dimensions(avctx, width, height);
if (avctx->pix_fmt != AV_PIX_FMT_NONE) @@ -310,8 +359,13 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, if (image->comps[i].prec > avctx->bits_per_raw_sample) avctx->bits_per_raw_sample = image->comps[i].prec;
- if (ff_thread_get_buffer(avctx, &frame, 0) < 0) - goto done; + if (ctx->separate_fields && realloc_il_buffer && picture->data[0]) + av_frame_unref(picture); + + if (!ctx->separate_fields || + (ctx->separate_fields && (!ctx->curpict || realloc_il_buffer))) + if (ff_thread_get_buffer(avctx, &frame, 0) < 0) + goto done;
ctx->dec_params.cp_limit_decoding = NO_LIMITATION; ctx->dec_params.cp_reduce = avctx->lowres; @@ -341,28 +395,28 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, switch (pixel_size) { case 1: if (ispacked) { - libopenjpeg_copy_to_packed8(picture, image); + libopenjpeg_copy_to_packed8(picture, image, ctx->separate_fields, field_pos); } else { - libopenjpeg_copyto8(picture, image); + libopenjpeg_copyto8(picture, image, ctx->separate_fields, field_pos); } break; case 2: if (ispacked) { - libopenjpeg_copy_to_packed8(picture, image); + libopenjpeg_copy_to_packed8(picture, image, ctx->separate_fields, field_pos); } else { - libopenjpeg_copyto16(picture, image); + libopenjpeg_copyto16(picture, image, ctx->separate_fields, field_pos); } break; case 3: case 4: if (ispacked) { - libopenjpeg_copy_to_packed8(picture, image); + libopenjpeg_copy_to_packed8(picture, image, ctx->separate_fields, field_pos); } break; case 6: case 8: if (ispacked) { - libopenjpeg_copy_to_packed16(picture, image); + libopenjpeg_copy_to_packed16(picture, image, ctx->separate_fields, field_pos); } break; default: @@ -373,7 +427,13 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, *got_frame = 1; ret = buf_size;
+ if (ctx->separate_fields) + if (field_nb) + av_frame_ref(data, ctx->picture); + else + *got_frame = 0; done: + ctx->curpict++; opj_image_destroy(image); opj_destroy_decompress(dec); return ret; @@ -401,6 +461,7 @@ AVCodec ff_libopenjpeg_decoder = { .priv_data_size = sizeof(LibOpenJPEGContext), .init = libopenjpeg_decode_init, .decode = libopenjpeg_decode_frame, + .close = libopenjpeg_decode_uninit, .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS, .max_lowres = 31, .long_name = NULL_IF_CONFIG_SMALL("OpenJPEG JPEG 2000"), -- 1.8.2
New patch attached. Extradata size check was incorrect in libopenjpegdec_decode_init function.
participants (4)
-
Carl Eugen Hoyos -
Matthieu Bouron -
Michael Niedermayer -
Tomas Härdin