From patchwork Sun Jun 18 01:25:45 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hein-Pieter van Braam X-Patchwork-Id: 4014 Delivered-To: ffmpegpatchwork@gmail.com Received: by 10.103.22.4 with SMTP id 4csp298800vsw; Sat, 17 Jun 2017 18:26:38 -0700 (PDT) X-Received: by 10.28.66.196 with SMTP id k65mr10759178wmi.55.1497749198280; Sat, 17 Jun 2017 18:26:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1497749198; cv=none; d=google.com; s=arc-20160816; b=dhOIJQbHHuYDmV1dKBAsyMkfAf0kyI/JWkxWZba+kUehEakYDu8X17DwJgTzJfagoh 0y0tiAYqWNaQOWsVveYv6fuVVj13whyh4BTxwpL7ZU3UGwt4H8YGZaKdY++05xEVghZe ergpTDrfRkS0sIxY2+8GkPfTiIRhPkgOIKPbV3jHg+iKPsASU51WLYk13wHA8zBNzGEO eGk8kf0zBhXSxVom1HhyUIfHgZdVq+2Ffw3CCuItRyFMDmsQVUW8lKIwBrbb5MrLieaz TNQvuAanGiz4DSx36Y5OTr+bl4nKjuLmP91igTtHXgetvVqcot1cLuK2Nm4MdSTkICPD ePtg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:dkim-filter:delivered-to :arc-authentication-results; bh=l2LwMKg1fYQ+jlc/9gL33/qUBe3xBB0W7059VwU8+XQ=; b=w/L6ZqNzbi6H7Dcy7R+thlu/9N4sg1Pv8bS8xAdS+dOT+y44zyRjDstxaTZo1bs8ii WGdeNm8TPB7C9wD5SFb4UGOMroNjbcYDSjhcBVkq5OyY8DsLWKkmmCU7paFSIHsSwoip vO+3rCY3mpr6EagkhEWLPZmJ3YHPq3CubDQLFpQVu4F3/Q2w3cwg9dVQQz2AZPS3fdFj l+hwYT+zC9mbSrxBjWhup4QmCmexCNYt+7bnEl6EYWHxnvtYRY7YxrzgZ8pc/0Lp/UJn n//ikAmTdA9NzQ68636z0+s4GzGq7Xp52jSpRfq54BI5XMssXo/YvVc7vG5eU9PDiUef Nb/A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@tmm.cx header.b=QjP2pZ3K; 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 sp=REJECT dis=NONE) header.from=tmm.cx Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id i22si5864700wrb.314.2017.06.17.18.26.37; Sat, 17 Jun 2017 18:26:38 -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=@tmm.cx header.b=QjP2pZ3K; 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 sp=REJECT dis=NONE) header.from=tmm.cx Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 9C7706803CB; Sun, 18 Jun 2017 04:25:55 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from eva.tmm.cx (eva.tmm.cx [5.9.73.21]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3C5A3689F68 for ; Sun, 18 Jun 2017 04:25:47 +0300 (EEST) Received: from lola.ttg.global (unknown [92.110.172.3]) by eva.tmm.cx (Postfix) with ESMTPSA id B56FF17CE637; Sun, 18 Jun 2017 01:25:50 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 eva.tmm.cx B56FF17CE637 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tmm.cx; s=mail; t=1497749151; bh=VacSVg4N2C93GqTfIJYDpRN43XCGnr3ntWeu4CiPhpY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QjP2pZ3KPc22CJJjnr28RbDbPuzww0NCzkSBYqcZFIWR22KcGkn4/18we/8SD782K RVGXxNdd7d9C52NtFdsiRoTR/VUFRhHSHJXStMdSAWH+4hW62XU3teVVWngypJCFXi Vbf8zNL1J+OhTTzaomem3Y5pguUzeabvIAXIPxEw= From: Hein-Pieter van Braam To: FFmpeg development discussions and patches Date: Sun, 18 Jun 2017 03:25:45 +0200 Message-Id: <20170618012547.13614-4-hp@tmm.cx> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20170618012547.13614-1-hp@tmm.cx> References: <20170618012547.13614-1-hp@tmm.cx> X-Spam-Status: No, score=0.0 required=2.4 tests=UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.1 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on eva.tmm.cx Subject: [FFmpeg-devel] [PATCH 3/5] Interplay MVE: Implement frame format 0x06 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 Cc: Hein-Pieter van Braam MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This implements the 0x06 frame format for Interplay MVE movies. The format is relatively simple. The video data consists of two parts: 16 bits per 8x8 block movement data a number of 8x8 blocks of pixel data For each 8x8 block of pixel data the movement data is consulted. There are 3 possible meanings of the movement data: * zero : copy the 8x8 block from the pixel data * negative : copy the 8x8 block from the previous frame from an offset determined by the actual value of the entry -0xC000. * positive : copy the 8x8 block from the current frame from an offset determined by the actual value of the entry -0x4000 Decoding happens in two passes, in the fist pass only new pixeldata is copied, during the second pass data is copied from the previous and current frames. The codec expects that the current frame being decoded to still has the data from 2 frames ago on it when decoding starts. Signed-off-by: Hein-Pieter van Braam --- libavcodec/interplayvideo.c | 125 ++++++++++++++++++++++++++++++++++++++++---- libavformat/ipmovie.c | 15 ++++-- 2 files changed, 126 insertions(+), 14 deletions(-) diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c index fb2d6fc..e227533 100644 --- a/libavcodec/interplayvideo.c +++ b/libavcodec/interplayvideo.c @@ -903,7 +903,82 @@ static int (* const ipvideo_decode_block16[])(IpvideoContext *s, AVFrame *frame) ipvideo_decode_block_opcode_0xE_16, ipvideo_decode_block_opcode_0x1, }; -static void ipvideo_decode_opcodes(IpvideoContext *s, AVFrame *frame) +static void ipvideo_format_06_firstpass(IpvideoContext *s, AVFrame *frame, short opcode) +{ + int line; + + if (! opcode) { + for (line = 0; line < 8; ++line) { + bytestream2_get_buffer(&s->stream_ptr, s->pixel_ptr, 8); + s->pixel_ptr += s->stride; + } + } else { + /* Don't try to copy second_last_frame data on the first frames */ + if (s->avctx->frame_number > 2) + copy_from(s, s->second_last_frame, frame, 0, 0); + } +} + +static void ipvideo_format_06_secondpass(IpvideoContext *s, AVFrame *frame, short opcode) +{ + int off_x, off_y; + + if (opcode < 0) { + off_x = ((unsigned short)opcode - 0xC000) % frame->linesize[0]; + off_y = ((unsigned short)opcode - 0xC000) / frame->linesize[0]; + copy_from(s, s->last_frame, frame, off_x, off_y); + } + if (opcode > 0) { + off_x = ((unsigned short)opcode - 0x4000) % frame->linesize[0]; + off_y = ((unsigned short)opcode - 0x4000) / frame->linesize[0]; + copy_from(s, frame, frame, off_x, off_y); + } +} + +static void (* const ipvideo_format_06_passes[])(IpvideoContext *s, AVFrame *frame, short op) = { + ipvideo_format_06_firstpass, ipvideo_format_06_secondpass, +}; + +static void ipvideo_decode_format_06_opcodes(IpvideoContext *s, AVFrame *frame) +{ + int pass, x, y; + short opcode; + GetByteContext decoding_map_ptr; + + /* this is PAL8, so make the palette available */ + memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); + s->stride = frame->linesize[0]; + + s->line_inc = s->stride - 8; + s->upper_motion_limit_offset = (s->avctx->height - 8) * frame->linesize[0] + + (s->avctx->width - 8) * (1 + s->is_16bpp); + + bytestream2_init(&decoding_map_ptr, s->decoding_map, s->decoding_map_size); + + for (pass = 0; pass < 2; ++pass) { + bytestream2_seek(&decoding_map_ptr, 0, SEEK_SET); + for (y = 0; y < s->avctx->height; y += 8) { + for (x = 0; x < s->avctx->width; x += 8) { + opcode = bytestream2_get_le16(&decoding_map_ptr); + + ff_tlog(s->avctx, + " block @ (%3d, %3d): opcode 0x%X, data ptr offset %d\n", + x, y, opcode, bytestream2_tell(&s->stream_ptr)); + + s->pixel_ptr = frame->data[0] + x + y*frame->linesize[0]; + ipvideo_format_06_passes[pass](s, frame, opcode); + } + } + } + + if (bytestream2_get_bytes_left(&s->stream_ptr) > 1) { + av_log(s->avctx, AV_LOG_DEBUG, + "decode finished with %d bytes left over\n", + bytestream2_get_bytes_left(&s->stream_ptr)); + } +} + +static void ipvideo_decode_format_11_opcodes(IpvideoContext *s, AVFrame *frame) { int x, y; unsigned char opcode; @@ -1007,18 +1082,39 @@ static int ipvideo_decode_frame(AVCodecContext *avctx, video_data_size = AV_RL16(buf + 2); s->decoding_map_size = AV_RL16(buf + 4); - if (frame_format != 0x11) - av_log(avctx, AV_LOG_ERROR, "Frame type 0x%02X unsupported\n", frame_format); + switch(frame_format) { + case 0x06: + if (s->decoding_map_size) { + av_log(avctx, AV_LOG_ERROR, "Decoding map for format 0x06\n"); + return AVERROR_INVALIDDATA; + } - if (! s->decoding_map_size) { - av_log(avctx, AV_LOG_ERROR, "Empty decoding map\n"); - return AVERROR_INVALIDDATA; - } + if (s->is_16bpp) { + av_log(avctx, AV_LOG_ERROR, "Video format 0x06 does not support 16bpp movies\n"); + return AVERROR_INVALIDDATA; + } + + /* Decoding map for 0x06 frame format is at the top of pixeldata */ + s->decoding_map_size = ((s->avctx->width / 8) * (s->avctx->height / 8)) * 2; + s->decoding_map = buf + 6 + 14; /* 14 bits of op data */ + bytestream2_init(&s->stream_ptr, buf + 6 + s->decoding_map_size + 14, video_data_size); - bytestream2_init(&s->stream_ptr, buf + 6, video_data_size); + break; - /* decoding map contains 4 bits of information per 8x8 block */ - s->decoding_map = buf + 6 + video_data_size; + case 0x11: + if (! s->decoding_map_size) { + av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x11\n"); + return AVERROR_INVALIDDATA; + } + + bytestream2_init(&s->stream_ptr, buf + 6, video_data_size); + s->decoding_map = buf + 6 + video_data_size; + + break; + + default: + av_log(avctx, AV_LOG_ERROR, "Frame type 0x%02X unsupported\n", frame_format); + } /* compressed buffer needs to be large enough to at least hold an entire * decoding map */ @@ -1039,7 +1135,14 @@ static int ipvideo_decode_frame(AVCodecContext *avctx, } } - ipvideo_decode_opcodes(s, frame); + switch(frame_format) { + case 0x06: + ipvideo_decode_format_06_opcodes(s, frame); + break; + case 0x11: + ipvideo_decode_format_11_opcodes(s, frame); + break; + } *got_frame = send_buffer; diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c index 23f5d68..6f4d90c 100644 --- a/libavformat/ipmovie.c +++ b/libavformat/ipmovie.c @@ -58,7 +58,7 @@ #define OPCODE_INIT_AUDIO_BUFFERS 0x03 #define OPCODE_START_STOP_AUDIO 0x04 #define OPCODE_INIT_VIDEO_BUFFERS 0x05 -#define OPCODE_UNKNOWN_06 0x06 +#define OPCODE_VIDEO_DATA_06 0x06 #define OPCODE_SEND_BUFFER 0x07 #define OPCODE_AUDIO_FRAME 0x08 #define OPCODE_SILENCE_FRAME 0x09 @@ -444,7 +444,6 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, s->video_width, s->video_height); break; - case OPCODE_UNKNOWN_06: case OPCODE_UNKNOWN_0E: case OPCODE_UNKNOWN_10: case OPCODE_UNKNOWN_12: @@ -537,8 +536,18 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, avio_skip(pb, opcode_size); break; + case OPCODE_VIDEO_DATA_06: + av_log(s->avf, AV_LOG_TRACE, "set video data format 0x06\n"); + s->frame_format = 0x06; + + /* log position and move on for now */ + s->video_chunk_offset = avio_tell(pb); + s->video_chunk_size = opcode_size; + avio_skip(pb, opcode_size); + break; + case OPCODE_VIDEO_DATA_11: - av_log(s->avf, AV_LOG_TRACE, "set video data\n"); + av_log(s->avf, AV_LOG_TRACE, "set video data format 0x11\n"); s->frame_format = 0x11; /* log position and move on for now */