Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions doc/reST/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2767,6 +2767,32 @@ Bitstream options
Emit SEI messages in a single NAL unit instead of multiple NALs. Default disabled.
When HRD SEI is enabled the HM decoder will throw a warning.

.. option:: --frame-packing <integer>

Emit the frame packing arrangement SEI message (H.265 D.2.16, D.3.16) that
tells the decoder how the two views of a stereoscopic video are packed into
the coded pictures. Frame 0 is always the left view. The values are those
that H.265 defines (Table D.8), any other value is an error:

3. Side by side: the left view is on the left, the right view on the right.
4. Top and bottom: the left view is on top, the right view on the bottom.
5. Temporal interleaving: alternate frames in output order are the left
and right views.

Types 3 and 4 write the message with each IRAP picture, and it persists until
the next one or the end of the coded video sequence. Type 5 writes it with every picture, because
current_frame_is_frame0_flag alternates with the frame. The first encoded
picture is the left view, so an odd :option:`--seek` swaps the views.
With :option:`--interlace` both fields of a frame belong to the same view,
whether the input pictures are already fields or :option:`--field` splits
each input frame into fields.

The message is written on the base layer only, so with :option:`--alpha` the
alpha layer does not carry it. It cannot be combined with
:option:`--num-views` greater than 1: each layer is then a full view and the
message would describe it as packed, so x265 gives an error.
The source must already be packed this way, x265 only signals it. Default disabled.

.. option:: --film-grain <filename>

Refers to the film grain model characteristics for signal enhancement information transmission.
Expand Down
2 changes: 1 addition & 1 deletion source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)
option(STATIC_LINK_CRT "Statically link C and C++ runtimes for release builds" OFF)
mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
# X265_BUILD must be incremented each time the public API is changed
set(X265_BUILD 217)
set(X265_BUILD 218)
configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
"${PROJECT_BINARY_DIR}/x265.def")
configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
Expand Down
10 changes: 10 additions & 0 deletions source/common/param.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ void x265_param_default(x265_param* param)

/* SEI messages */
param->preferredTransferCharacteristics = -1;
param->framePacking = -1;
param->pictureStructure = -1;
param->bEmitCLL = 1;

Expand Down Expand Up @@ -1436,6 +1437,7 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)
OPT("dynamic-refine") p->bDynamicRefine = atobool(value);
OPT("single-sei") p->bSingleSeiNal = atobool(value);
OPT("atc-sei") p->preferredTransferCharacteristics = atoi(value);
OPT("frame-packing") p->framePacking = atoi(value);
OPT("pic-struct") p->pictureStructure = atoi(value);
OPT("chunk-start") p->chunkStart = atoi(value);
OPT("chunk-end") p->chunkEnd = atoi(value);
Expand Down Expand Up @@ -2024,6 +2026,7 @@ int x265_check_params(x265_param* param)
|| param->bEmitIDRRecoverySEI
|| !!param->interlaceMode
|| param->preferredTransferCharacteristics > 1
|| param->framePacking > -1
|| strlen(param->toneMapFile)
|| strlen(param->naluFile));

Expand All @@ -2032,6 +2035,10 @@ int x265_check_params(x265_param* param)
param->bSingleSeiNal = 0;
x265_log(param, X265_LOG_WARNING, "None of the SEI messages are enabled. Disabling Single SEI NAL\n");
}
CHECK(param->framePacking != -1 && (param->framePacking < 3 || param->framePacking > 5),
"Frame packing arrangement type must be 3 (side by side), 4 (top and bottom) or 5 (temporal interleaving)");
CHECK(param->framePacking != -1 && param->numViews > 1,
"Frame packing arrangement SEI cannot be used with multi-view encoding, each layer is a full view");
CHECK(param->confWinRightOffset < 0, "Conformance Window Right Offset must be 0 or greater");
CHECK(param->confWinBottomOffset < 0, "Conformance Window Bottom Offset must be 0 or greater");
CHECK(param->decoderVbvMaxRate < 0, "Invalid Decoder Vbv Maxrate. Value can not be less than zero");
Expand Down Expand Up @@ -2508,6 +2515,8 @@ char *x265_param2string(x265_param* p, int padx, int pady)
BOOL(p->bHDR10Opt, "hdr10-opt");
BOOL(p->bDhdr10opt, "dhdr10-opt");
BOOL(p->bEmitIDRRecoverySEI, "idr-recovery-sei");
if (p->framePacking > -1)
s += snprintf(s, bufSize - (s - buf), " frame-packing=%d", p->framePacking);
if (strlen(p->analysisSave))
s += snprintf(s, bufSize - (s - buf), " analysis-save");
if (strlen(p->analysisLoad))
Expand Down Expand Up @@ -2897,6 +2906,7 @@ void x265_copy_params(x265_param* dst, x265_param* src)
dst->cbQpOffset = src->cbQpOffset;
dst->crQpOffset = src->crQpOffset;
dst->preferredTransferCharacteristics = src->preferredTransferCharacteristics;
dst->framePacking = src->framePacking;
dst->pictureStructure = src->pictureStructure;

dst->rc.rateControlMode = src->rc.rateControlMode;
Expand Down
16 changes: 16 additions & 0 deletions source/encoder/frameencoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,21 @@ void FrameEncoder::compressFrame(int layer)
m_seiAlternativeTC.m_preferredTransferCharacteristics = m_param->preferredTransferCharacteristics;
m_seiAlternativeTC.writeSEImessages(m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList, m_param->bSingleSeiNal, layer);
}

/* The message describes the packed pictures of the base layer: an alpha layer is not a view. */
bool writeFramePacking = m_param->framePacking > -1 && !layer && (slice->isIRAP() || m_param->framePacking == 5);
if (writeFramePacking)
{
/* Type 5 alternates the views frame by frame, so every picture carries its own message. The
* other types persist until the next IRAP, which repeats the message. With --interlace the
* pictures are fields and both fields of a frame belong to the same view. */
int frameIdx = m_param->interlaceMode ? m_frame[layer]->m_poc >> 1 : m_frame[layer]->m_poc;
SEIFramePacking m_seiFramePacking;
m_seiFramePacking.m_arrangementType = m_param->framePacking;
m_seiFramePacking.m_currentFrameIsFrame0 = m_param->framePacking == 5 && !(frameIdx & 1);
m_seiFramePacking.m_persistence = m_param->framePacking != 5;
m_seiFramePacking.writeSEImessages(m_bs, *slice->m_sps, NAL_UNIT_PREFIX_SEI, m_nalList, m_param->bSingleSeiNal, layer);
}
/* Write Film grain characteristics if present */
if (this->m_top->m_filmGrainIn)
{
Expand Down Expand Up @@ -898,6 +913,7 @@ void FrameEncoder::compressFrame(int layer)

bool isSei = ((m_frame[layer]->m_lowres.bKeyframe && m_param->bRepeatHeaders) || m_param->bEmitHRDSEI ||
!!m_param->interlaceMode || (m_frame[layer]->m_lowres.sliceType == X265_TYPE_IDR && m_param->bEmitIDRRecoverySEI) ||
writeFramePacking ||
m_frame[layer]->m_userSEI.numPayloads);

if (isSei && m_param->bSingleSeiNal)
Expand Down
42 changes: 42 additions & 0 deletions source/encoder/sei.h
Original file line number Diff line number Diff line change
Expand Up @@ -902,5 +902,47 @@ class SEIAlternativeTC : public SEI
}
};

class SEIFramePacking : public SEI
{
public:
int m_arrangementType;
bool m_currentFrameIsFrame0;
bool m_persistence;
SEIFramePacking()
{
m_payloadType = FRAME_PACKING;
m_payloadSize = 0;
m_arrangementType = -1;
m_currentFrameIsFrame0 = false;
m_persistence = false;
}

// cppcheck-suppress missingOverride
void writeSEI(const SPS&)
{
WRITE_UVLC(0, "frame_packing_arrangement_id");
WRITE_FLAG(0, "frame_packing_arrangement_cancel_flag");
WRITE_CODE(m_arrangementType, 7, "frame_packing_arrangement_type");
WRITE_FLAG(0, "quincunx_sampling_flag");
WRITE_CODE(1, 6, "content_interpretation_type"); /* frame 0 is the left view */
WRITE_FLAG(0, "spatial_flipping_flag");
WRITE_FLAG(0, "frame0_flipped_flag");
WRITE_FLAG(0, "field_views_flag");
WRITE_FLAG(m_currentFrameIsFrame0, "current_frame_is_frame0_flag");
WRITE_FLAG(0, "frame0_self_contained_flag");
WRITE_FLAG(0, "frame1_self_contained_flag");
if (m_arrangementType != 5)
{
WRITE_CODE(0, 4, "frame0_grid_position_x");
WRITE_CODE(0, 4, "frame0_grid_position_y");
WRITE_CODE(0, 4, "frame1_grid_position_x");
WRITE_CODE(0, 4, "frame1_grid_position_y");
}
WRITE_CODE(0, 8, "frame_packing_arrangement_reserved_byte");
WRITE_FLAG(m_persistence, "frame_packing_arrangement_persistence_flag");
WRITE_FLAG(0, "upsampled_aspect_ratio_flag");
}
};

}
#endif // ifndef X265_SEI_H
6 changes: 6 additions & 0 deletions source/test/regression-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,9 @@ crowd_run_1080p50.y4m, --bitrate 5000 --selective-mcstf --preset veryslow
#Fovea tests
nature_1920x1080_25.yuv,--crf 28 --fovea-gaze 960,540 --fovea-delta 20
nature_1920x1080_25.yuv,--qp 28 --fovea-delta 20 --fovea-gaze-file gaze_nature.txt

#Frame packing arrangement SEI tests
big_buck_bunny_360p24.y4m,--preset ultrafast --frame-packing 3
big_buck_bunny_360p24.y4m,--preset superfast --bframes 4 --frame-packing 4
big_buck_bunny_360p24.y4m,--preset veryfast --frame-packing 5
big_buck_bunny_360p24.y4m,--preset veryfast --b-adapt 2 --bframes 0 --interlace tff --field --frame-packing 5
3 changes: 3 additions & 0 deletions source/test/smoke-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ CrowdRun_1920x1080_50_10bit_444.yuv,--preset=superfast --bitrate 7000 --sao --li

#Threaded ME tests
BasketballDrive_1920x1080_50.y4m,--preset=superfast --threaded-me --rect --amp --qp 28

#Frame packing arrangement SEI test
big_buck_bunny_360p24.y4m,--preset ultrafast --frame-packing 3
11 changes: 11 additions & 0 deletions source/x265.h
Original file line number Diff line number Diff line change
Expand Up @@ -2403,6 +2403,17 @@ typedef struct x265_param
* When set, overrides foveaGazeX/foveaGazeY with per-frame values.
* NULL = use static gaze from foveaGazeX/foveaGazeY. */
char* foveaGazeFile;

/* Frame packing arrangement SEI message (H.265 D.2.16): the 3D layout of the
* source frames. 3 = side by side, 4 = top and bottom (frame 0 is the left view),
* 5 = temporal interleaving (alternate frames are the left and right views).
* The first encoded picture is the left view, so an odd --seek swaps the views.
* With interlaceMode both fields of a frame belong to the same view.
* Other values are an error.
* Types 3 and 4 write the message with each IRAP picture, type 5 with every
* picture. It is written on the base layer only and cannot be combined with
* numViews > 1. Default -1 (disabled). */
int framePacking;
} x265_param;

/* x265_param_alloc:
Expand Down
5 changes: 5 additions & 0 deletions source/x265cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,11 @@ namespace X265_NS {
H0(" --[no-]eos Emit end of sequence nal unit at the end of every coded video sequence. Default %s\n", OPT(param->bEnableEndOfSequence));
H1(" --hash <integer> Decoded Picture Hash SEI 0: disabled, 1: MD5, 2: CRC, 3: Checksum. Default %d\n", param->decodedPictureHashSEI);
H0(" --atc-sei <integer> Emit the alternative transfer characteristics SEI message where the integer is the preferred transfer characteristic. Default disabled\n");
H0(" --frame-packing <integer> Emit the frame packing arrangement SEI message for stereoscopic video. Other values are an error. Default disabled\n");
H0(" - 3: side by side - left view on the left, right view on the right\n");
H0(" - 4: top and bottom - left view on top, right view on the bottom\n");
H0(" - 5: temporal interleaving - alternate frames are the left and right views. The first encoded picture is the left view\n");
H0(" An odd --seek swaps the views. With --interlace both fields of a frame belong to the same view\n");
H0(" --pic-struct <integer> Set the picture structure and emit it in the picture timing SEI message. Values in the range 0..12. See D.3.3 of the HEVC spec. for a detailed explanation.\n");
H0(" --log2-max-poc-lsb <integer> Maximum of the picture order count\n");
H0(" --[no-]vui-timing-info Emit VUI timing information in the bitstream. Default %s\n", OPT(param->bEmitVUITimingInfo));
Expand Down
1 change: 1 addition & 0 deletions source/x265cli.h
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ static const struct option long_options[] =
{ "single-sei", no_argument, NULL, 0 },
{ "no-single-sei", no_argument, NULL, 0 },
{ "atc-sei", required_argument, NULL, 0 },
{ "frame-packing", required_argument, NULL, 0 },
{ "pic-struct", required_argument, NULL, 0 },
{ "nalu-file", required_argument, NULL, 0 },
{ "dolby-vision-rpu", required_argument, NULL, 0 },
Expand Down
Loading