From patchwork Fri Oct 7 19:31:46 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vittorio Giovara X-Patchwork-Id: 906 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.140.66 with SMTP id o63csp1558784vsd; Fri, 7 Oct 2016 12:32:01 -0700 (PDT) X-Received: by 10.28.152.2 with SMTP id a2mr248187wme.66.1475868721811; Fri, 07 Oct 2016 12:32:01 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id mu9si23697121wjb.18.2016.10.07.12.31.57; Fri, 07 Oct 2016 12:32:01 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 9D63D689CC4; Fri, 7 Oct 2016 22:31:39 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qk0-f194.google.com (mail-qk0-f194.google.com [209.85.220.194]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 37887689CA2 for ; Fri, 7 Oct 2016 22:31:33 +0300 (EEST) Received: by mail-qk0-f194.google.com with SMTP id n66so3134350qkf.0 for ; Fri, 07 Oct 2016 12:31:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id:in-reply-to:references; bh=TK2aHoQigMlvQkEPT3qTLa77ak2plbDG6J3/blSmE6I=; b=P5BPbaWd3NXc28IpziR0EpMu+1dfJ9xVLxVd3l9/YsocgRW15sBH+tKgvFudXakMUG Cdvki7eCeCoMiI3zkf07/T7ti2R7ERN4hFh6/UBielfuEsYMkPIkPVzwi5C+IQpVX2zS 1DP2RYDheFfZ4Rf+LweImm/2BudHm3H/NFk9fOkqaMaMD42TkfqliCI7PLlEGHs4rcRJ 8s2Sm2KdezoKU2gHdSgkOPbKhIalwAVdZxekqIg8RROdy1NOk7T3e6U9TuZHKm+lD+LF e7V/76O61MU7IU78tjIfOQlgdP1iloCvo2yKErf/W4HsyHRkr1uaADrNmbEIVsv+SB/I uOog== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=TK2aHoQigMlvQkEPT3qTLa77ak2plbDG6J3/blSmE6I=; b=HRohUmqb/V29+qW39xNfe97DN2zgOxpHicqVqIj1BLZVWOelNZMOziZelZ1mcKL2gA 1n9NixpuhS/WMDqGgIujRkoxXtfJWF9+kveCBlgkSk8/E5nNDzagxvQM2LQDce//5Boy RrNhfR2HdsXYqqCfcb6hxW5ynB+PVn+J1HIwZ2xtAk7nmIlqzC+S0WBZkMjy3+UJMSPx qSG028t+DysoPjD1Xw6U7xwJA93I8/4LH/n1H3ian6WJ4jTVC3XpeHzdqfz2TGc6Gft4 GcXMj9sZFzIo2saayFISelPNufp+BZdT56+gGhBprnR1i3Dfr+PcryBoI5PQ6Qujd4JG tLvw== X-Gm-Message-State: AA6/9RnDT0Q78/rdtuZQ1f2vxgWlaCqTRffzovYKkHb88xJqvATJ7KG5VibHAhWTSnLX9g== X-Received: by 10.55.195.207 with SMTP id r76mr20056068qkl.312.1475868707661; Fri, 07 Oct 2016 12:31:47 -0700 (PDT) Received: from vimacbookpro.vimeo.iac.corp ([216.112.253.9]) by smtp.gmail.com with ESMTPSA id y33sm3123018qtc.34.2016.10.07.12.31.46 for (version=TLS1 cipher=AES128-SHA bits=128/128); Fri, 07 Oct 2016 12:31:47 -0700 (PDT) From: Vittorio Giovara To: ffmpeg-devel@ffmpeg.org Date: Fri, 7 Oct 2016 15:31:46 -0400 Message-Id: <20161007193146.93184-1-vittorio.giovara@gmail.com> X-Mailer: git-send-email 2.10.0 In-Reply-To: <20161006231039.GH5270@nb4> References: <20161006231039.GH5270@nb4> Subject: [FFmpeg-devel] [PATCH] mov: Evaluate the movie display matrix X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This matrix needs to be applied after all others have (currently only display matrix from trak), but cannot be handled in movie box, since streams are not allocated yet. So store it in main context and if not identity, apply it when appropriate, handling the case when trak display matrix is identity and when it is not. Signed-off-by: Vittorio Giovara --- Updated according review. Vittorio libavformat/isom.h | 2 ++ libavformat/mov.c | 63 +++++++++++++++++++++++++++------ tests/fate/mov.mak | 6 +++- tests/ref/fate/mov-movie-display-matrix | 10 ++++++ 4 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 tests/ref/fate/mov-movie-display-matrix diff --git a/libavformat/isom.h b/libavformat/isom.h index 2246fed..2aeb8fa 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -238,6 +238,8 @@ typedef struct MOVContext { uint8_t *decryption_key; int decryption_key_len; int enable_drefs; + + int32_t movie_display_matrix[3][3]; ///< display matrix from mvhd } MOVContext; int ff_mp4_read_descr_len(AVIOContext *pb); diff --git a/libavformat/mov.c b/libavformat/mov.c index a15c8d1..307ce08 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -1211,6 +1211,7 @@ static int mov_read_mdhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) { + int i; int64_t creation_time; int version = avio_r8(pb); /* version */ avio_rb24(pb); /* flags */ @@ -1238,7 +1239,12 @@ static int mov_read_mvhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_skip(pb, 10); /* reserved */ - avio_skip(pb, 36); /* display matrix */ + /* movie display matrix, store it in main context and use it later on */ + for (i = 0; i < 3; i++) { + c->movie_display_matrix[i][0] = avio_rb32(pb); // 16.16 fixed point + c->movie_display_matrix[i][1] = avio_rb32(pb); // 16.16 fixed point + c->movie_display_matrix[i][2] = avio_rb32(pb); // 2.30 fixed point + } avio_rb32(pb); /* preview time */ avio_rb32(pb); /* preview duration */ @@ -3798,9 +3804,24 @@ static int mov_read_meta(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +// return 0 when matrix is identity, 1 otherwise +#define IS_MATRIX_FULL(matrix) \ + (matrix[0][0] != (1 << 16) || \ + matrix[1][1] != (1 << 16) || \ + matrix[2][2] != (1 << 30) || \ + matrix[0][1] || matrix[0][2] || \ + matrix[1][0] || matrix[1][2] || \ + matrix[2][0] || matrix[2][1]) + +// fixed point to int64_t +#define CONV_FP2INT(x, sh) ((int64_t) (x)) / (1 << sh) + +// int64_t to fixed point +#define CONV_INT2FP(x, sh) (int32_t) ((x) * (1 << sh)) + static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - int i; + int i, j, e; int width; int height; int display_matrix[3][3]; @@ -3855,13 +3876,7 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) // save the matrix and add rotate metadata when it is not the default // identity - if (display_matrix[0][0] != (1 << 16) || - display_matrix[1][1] != (1 << 16) || - display_matrix[2][2] != (1 << 30) || - display_matrix[0][1] || display_matrix[0][2] || - display_matrix[1][0] || display_matrix[1][2] || - display_matrix[2][0] || display_matrix[2][1]) { - int i, j; + if (IS_MATRIX_FULL(display_matrix)) { double rotate; av_freep(&sc->display_matrix); @@ -3884,13 +3899,41 @@ static int mov_read_tkhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) } } + // if movie display matrix is not identity, and if this is a video track + if (IS_MATRIX_FULL(c->movie_display_matrix) && width && height) { + // if trak display matrix was identity, just copy the movie one + if (!sc->display_matrix) { + sc->display_matrix = av_malloc(sizeof(int32_t) * 9); + if (!sc->display_matrix) + return AVERROR(ENOMEM); + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + sc->display_matrix[i * 3 + j] = c->movie_display_matrix[i][j]; + } else { // otherwise multiply the two and store the result + int64_t val = 0; + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + int sh = j == 2 ? 30 : 16; + for (e = 0; e < 3; e++) { + val += CONV_FP2INT(display_matrix[i][e], sh) * + CONV_FP2INT(c->movie_display_matrix[e][j], sh); + } + sc->display_matrix[i * 3 + j] = CONV_INT2FP(val, sh); + val = 0; + } + } + } + } + // transform the display width/height according to the matrix // to keep the same scale, use [width height 1<<16] if (width && height && sc->display_matrix) { double disp_transform[2]; for (i = 0; i < 2; i++) - disp_transform[i] = hypot(display_matrix[i][0], display_matrix[i][1]); + disp_transform[i] = hypot(sc->display_matrix[i * 3], + sc->display_matrix[i * 3 + 1]); if (disp_transform[0] > 0 && disp_transform[1] > 0 && disp_transform[0] < (1<<24) && disp_transform[1] < (1<<24) && diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak index 4b5885b..3210ea6 100644 --- a/tests/fate/mov.mak +++ b/tests/fate/mov.mak @@ -4,7 +4,8 @@ FATE_MOV = fate-mov-3elist \ fate-mov-1elist-noctts \ fate-mov-elist-starts-ctts-2ndsample \ fate-mov-1elist-ends-last-bframe \ - fate-mov-2elist-elist1-ends-bframe + fate-mov-2elist-elist1-ends-bframe \ + fate-mov-movie-display-matrix \ FATE_SAMPLES_AVCONV += $(FATE_MOV) @@ -26,3 +27,6 @@ fate-mov-1elist-ends-last-bframe: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-1e # Makes sure that we handle timestamps of packets in case of multiple edit lists with one of them ending on a B-frame correctly. fate-mov-2elist-elist1-ends-bframe: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-2elist-elist1-ends-bframe.mov + +# File contains a movie display matrix +fate-mov-movie-display-matrix: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/moviedispmat.mp4 -frames 1 diff --git a/tests/ref/fate/mov-movie-display-matrix b/tests/ref/fate/mov-movie-display-matrix new file mode 100644 index 0000000..4ca0308 --- /dev/null +++ b/tests/ref/fate/mov-movie-display-matrix @@ -0,0 +1,10 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 540x576 +#sar 0: 93207/65536 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 466560, e3ec6c8f40c864b41edbdd438d642ac0