From patchwork Tue Oct 9 13:32:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: joshdk@ob-encoder.com X-Patchwork-Id: 10595 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:ab0:73d2:0:0:0:0:0 with SMTP id m18csp4918821uaq; Tue, 9 Oct 2018 06:38:31 -0700 (PDT) X-Google-Smtp-Source: ACcGV608AkKGi0DhWaMwqE8vPMwEOsma4vvZckXsrPPNtkeIzMrzDzgD7c8YqXYLzZUZL1lqVJi+ X-Received: by 2002:a05:6000:1008:: with SMTP id a8mr11287054wrx.271.1539092311671; Tue, 09 Oct 2018 06:38:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1539092311; cv=none; d=google.com; s=arc-20160816; b=cYNl33UvqDhKPjVGSnF6P/40ecNon4Oq3dGf7+GOh6HQf35m0qSaT97TI7UY1AhZ8I tVWwjfsD2BIc8124abCeNm8Xpw5jbY1tVm0looEXGyHB2sOnTxPBS/D6kd6Num26tJuz iHA0+DkcgGu+fTBFCjeZM2U+70ebmOGUwS7fcetmeM0hpjS3yt0TT7kizM+FNMnGQml5 Qgf5lWn6mj7WRbEIT/EkENUtjFSTwzGh4wT3o2Bp7DmP4qP3xb1qdge6U3pjXBVTIqku f3i62oldKuYEgxjWyN97sYg6nHO7iV3dJ8bvbGnbjdW+kJgSjvrsLKVMlw3KauJCVwf+ TGYg== 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:delivered-to; bh=JQ5F9MPMWt+jGkc+9gcwmhjMYV18AdIEG4uk0ejWs20=; b=NO2WREuDfbkqNjpuDBDtOJ33ZdxDHTgMLJBXsWFGYzuc20L311QtcdxhwAjoTHqM4A m03fU3Axri8FK/TmZ3aUZgd2dAvuolH7rw0O1YCLJX57wnktaLZ2NUIW8pwTL2boM4SW qIViYulvgJfBTxbX46P3uXmZgvs6UkMXjHeN8Gqi3PUawSgoMY9G9rPizOjukNSheR+y oMQNLYoQqP/pRLAyqr1blSX+yNKPTesd33BWpIE02+f06KtRcRYCBw1b3f6pyaObK+5k zJ67Ov9q5uvtSBLCWFvWLEXn1Di8t1eAXRo5vMWuB0i3+Jm/M20KPLWiegdzN2BORiPc npew== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@ob-encoder-com.20150623.gappssmtp.com header.s=20150623 header.b=NIJhXdic; 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 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id p4-v6si10155012wmd.47.2018.10.09.06.38.31; Tue, 09 Oct 2018 06:38:31 -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=@ob-encoder-com.20150623.gappssmtp.com header.s=20150623 header.b=NIJhXdic; 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 Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 216AF68A24C; Tue, 9 Oct 2018 16:38:08 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EC4E1689E51 for ; Tue, 9 Oct 2018 16:38:00 +0300 (EEST) Received: by mail-wr1-f50.google.com with SMTP id a13-v6so1875048wrt.5 for ; Tue, 09 Oct 2018 06:38:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ob-encoder-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Y4dViF19Cdtd1al8ITyI50h3WfliR4XdZRL3h17JFds=; b=NIJhXdicRdGHRZ27Gc9fnpBAWfiN/crGr64N6cjIfQazIQ4oHxVE1IhJdIckHfQ1kK +N18g3LnZ5W8xoWb4hJ4voUir56A/pM3hTgXXVOxod0HPXgk1KH7WFaMBGf5e6EpTzhP yMB2k5nIfgFYpeSAtqAllV/wzngQeVju5YxjjQnMspAg5Ar0qGqeU84LdAY4RAVnSodA cAF2OoctHMcgvhS8QsEngsFfwsLizeRJ7fIDcj18ZQycjuMLhXM723d2bNULAxchytQ8 3lkO64JdNXPcExCvHap8qHXbfUv7iCRIiDLZPJ+LYX3KLpfsX7Q6zWltczbIldaJg1e/ Y2RQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Y4dViF19Cdtd1al8ITyI50h3WfliR4XdZRL3h17JFds=; b=t0OBimCWB8NhExwKp0iyvxg9SBEB5JdxvpPRgdmRH6RA648mZje5Vmh3YSegPHWnJP N2Q+ZRq8GN/6urr/hFNIp+RJc6ntG3mAM6q3XQY+ppUy/Re2ZYXgQugSK3kuPkxOImLM iac5V3I/zhS717QplrG7/trxYq1ox9Os0EBCXzI46D2b814aP8nmpbXoXkAlRqMvNcpg uKqmn413OtP7LgLQbIjuh2iRdYZaPE0MY4BHxwJmOAvLsCTm1gPn+ugrCf2039h7ya+7 ACQvBFglp915ua9DUbcIFND9UQPJO6fORMjW8MbzketuKPCSByOJJ0+IeiZm2NQ1quOq gm4g== X-Gm-Message-State: ABuFfoiIQgOzi/ygg8MHU4EAbdcEOF7Y1MasePZ7j1eFm9nD3ZRslGIU tQ6htSxWSqXdEdzUIWru4fJgBV5jcMs= X-Received: by 2002:adf:e752:: with SMTP id c18-v6mr21707312wrn.143.1539091934027; Tue, 09 Oct 2018 06:32:14 -0700 (PDT) Received: from localhost.localdomain (cpc107625-sotn16-2-0-cust150.15-1.cable.virginm.net. [81.104.78.151]) by smtp.gmail.com with ESMTPSA id e133-v6sm18206731wma.42.2018.10.09.06.32.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 09 Oct 2018 06:32:13 -0700 (PDT) From: joshdk@ob-encoder.com X-Google-Original-From: joshdk@obe.tv To: ffmpeg-devel@ffmpeg.org Date: Tue, 9 Oct 2018 14:32:04 +0100 Message-Id: <20181009133204.29686-4-joshdk@obe.tv> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181009133204.29686-1-joshdk@obe.tv> References: <20181009133204.29686-1-joshdk@obe.tv> Subject: [FFmpeg-devel] [PATCH 3/3] h264/pic_timing: support multiple timecodes 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: Josh de Kock MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" From: Josh de Kock --- libavcodec/h264_sei.c | 21 ++++++++------ libavcodec/h264_sei.h | 28 +++++++++++++------ libavcodec/h264_slice.c | 59 ++++++++++++++++++++++----------------- libavfilter/vf_showinfo.c | 10 +++++++ 4 files changed, 75 insertions(+), 43 deletions(-) diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 275224eabe..d4eb9c0dab 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -84,8 +84,10 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, return AVERROR_INVALIDDATA; num_clock_ts = sei_num_clock_ts_table[h->pic_struct]; + h->timecode_cnt = 0; for (i = 0; i < num_clock_ts; i++) { if (get_bits(gb, 1)) { /* clock_timestamp_flag */ + H264SEITimeCode *tc = &h->timecode[h->timecode_cnt++]; unsigned int full_timestamp_flag; unsigned int counting_type, cnt_dropped_flag; h->ct_type |= 1 << get_bits(gb, 2); @@ -95,20 +97,21 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, skip_bits(gb, 1); /* discontinuity_flag */ cnt_dropped_flag = get_bits(gb, 1); /* cnt_dropped_flag */ if (cnt_dropped_flag && counting_type > 1 && counting_type < 7) - h->tc_dropframe = 1; - h->tc_frames = get_bits(gb, 8); /* n_frames */ + tc->dropframe = 1; + tc->frame = get_bits(gb, 8); /* n_frames */ if (full_timestamp_flag) { - h->fulltc_received = 1; - h->tc_seconds = get_bits(gb, 6); /* seconds_value 0..59 */ - h->tc_minutes = get_bits(gb, 6); /* minutes_value 0..59 */ - h->tc_hours = get_bits(gb, 5); /* hours_value 0..23 */ + tc->full = 1; + tc->seconds = get_bits(gb, 6); /* seconds_value 0..59 */ + tc->minutes = get_bits(gb, 6); /* minutes_value 0..59 */ + tc->hours = get_bits(gb, 5); /* hours_value 0..23 */ } else { + tc->seconds = tc->minutes = tc->hours = tc->full = 0; if (get_bits(gb, 1)) { /* seconds_flag */ - h->tc_seconds = get_bits(gb, 6); + tc->seconds = get_bits(gb, 6); if (get_bits(gb, 1)) { /* minutes_flag */ - h->tc_minutes = get_bits(gb, 6); + tc->minutes = get_bits(gb, 6); if (get_bits(gb, 1)) /* hours_flag */ - h->tc_minutes = get_bits(gb, 5); + tc->hours = get_bits(gb, 5); } } } diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h index 3b8806be0a..a75c3aa175 100644 --- a/libavcodec/h264_sei.h +++ b/libavcodec/h264_sei.h @@ -67,6 +67,17 @@ typedef enum { H264_SEI_FPA_TYPE_2D = 6, } H264_SEI_FpaType; +typedef struct H264SEITimeCode { + /* When not continuously receiving full timecodes, we have to reference + the previous timecode received */ + int full; + int frame; + int seconds; + int minutes; + int hours; + int dropframe; +} H264SEITimeCode; + typedef struct H264SEIPictureTiming { int present; H264_SEI_PicStructType pic_struct; @@ -88,14 +99,15 @@ typedef struct H264SEIPictureTiming { */ int cpb_removal_delay; - /* When not continuously receiving full timecodes, we have to reference - the previous timecode received */ - int fulltc_received; - int tc_frames; - int tc_seconds; - int tc_minutes; - int tc_hours; - int tc_dropframe; + /** + * Maximum three timecodes in a pic_timing SEI. + */ + H264SEITimeCode timecode[3]; + + /** + * Number of timecode in use + */ + int timecode_cnt; } H264SEIPictureTiming; typedef struct H264SEIAFD { diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 973f5761ef..aaf0006a32 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -1287,42 +1287,49 @@ static int h264_export_frame_props(H264Context *h) h->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; } - if (h->sei.picture_timing.fulltc_received) { + if (h->sei.picture_timing.timecode_cnt > 0) { uint32_t tc = 0; - uint32_t frames; + uint32_t *tc_sd; AVFrameSideData *tcside = av_frame_new_side_data(cur->f, AV_FRAME_DATA_S12M_TIMECODE, - sizeof(uint32_t)); + sizeof(uint32_t)*4); if (!tcside) return AVERROR(ENOMEM); - /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS. - See SMPTE ST 12-1:2014 Sec 12.1 for more info. */ - if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) { - frames = h->sei.picture_timing.tc_frames / 2; - if (h->sei.picture_timing.tc_frames % 2 == 1) { - if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0) - tc |= (1 << 7); - else - tc |= (1 << 23); + tc_sd = (uint32_t*)tcside->data; + tc_sd[0] = h->sei.picture_timing.timecode_cnt; + + for (int i = 0; i < tc_sd[0]; i++) { + uint32_t frames; + + /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS. + See SMPTE ST 12-1:2014 Sec 12.1 for more info. */ + if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) { + frames = h->sei.picture_timing.timecode[i].frame / 2; + if (h->sei.picture_timing.timecode[i].frame % 2 == 1) { + if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0) + tc |= (1 << 7); + else + tc |= (1 << 23); + } + } else { + frames = h->sei.picture_timing.timecode[i].frame; } - } else { - frames = h->sei.picture_timing.tc_frames; - } - tc |= h->sei.picture_timing.tc_dropframe << 30; - tc |= (frames / 10) << 28; - tc |= (frames % 10) << 24; - tc |= (h->sei.picture_timing.tc_seconds / 10) << 20; - tc |= (h->sei.picture_timing.tc_seconds % 10) << 16; - tc |= (h->sei.picture_timing.tc_minutes / 10) << 12; - tc |= (h->sei.picture_timing.tc_minutes % 10) << 8; - tc |= (h->sei.picture_timing.tc_hours / 10) << 4; - tc |= (h->sei.picture_timing.tc_hours % 10); + tc |= h->sei.picture_timing.timecode[i].dropframe << 30; + tc |= (frames / 10) << 28; + tc |= (frames % 10) << 24; + tc |= (h->sei.picture_timing.timecode[i].seconds / 10) << 20; + tc |= (h->sei.picture_timing.timecode[i].seconds % 10) << 16; + tc |= (h->sei.picture_timing.timecode[i].minutes / 10) << 12; + tc |= (h->sei.picture_timing.timecode[i].minutes % 10) << 8; + tc |= (h->sei.picture_timing.timecode[i].hours / 10) << 4; + tc |= (h->sei.picture_timing.timecode[i].hours % 10); - memcpy(tcside->data, &tc, sizeof(uint32_t)); - h->sei.picture_timing.fulltc_received = 0; + tc_sd[i + 1] = tc; + } + h->sei.picture_timing.timecode_cnt = 0; } if (h->sei.alternative_transfer.present && diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c index d1d1415c0b..689b5399db 100644 --- a/libavfilter/vf_showinfo.c +++ b/libavfilter/vf_showinfo.c @@ -32,6 +32,7 @@ #include "libavutil/spherical.h" #include "libavutil/stereo3d.h" #include "libavutil/timestamp.h" +#include "libavutil/timecode.h" #include "avfilter.h" #include "internal.h" @@ -174,6 +175,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) case AV_FRAME_DATA_STEREO3D: dump_stereo3d(ctx, sd); break; + case AV_FRAME_DATA_S12M_TIMECODE: { + uint32_t *tc = (uint32_t*)sd->data; + for (int j = 1; j < tc[0]; j++) { + char tcbuf[AV_TIMECODE_STR_SIZE]; + av_timecode_make_smpte_tc_string(tcbuf, tc[j], 0); + av_log(ctx, AV_LOG_INFO, "timecode - %s%s", tcbuf, j != tc[0] - 1 ? ", " : ""); + } + break; + } case AV_FRAME_DATA_DISPLAYMATRIX: av_log(ctx, AV_LOG_INFO, "displaymatrix: rotation of %.2f degrees", av_display_rotation_get((int32_t *)sd->data));