[FFmpeg-devel] [PATCH] avformat/mov: get heif image rotation from irot box
James Almer
jamrial at gmail.com
Wed Sep 25 03:14:46 EEST 2024
Based on a patch by Hacene Bouaroua.
Co-authored-by: Hacene Bouaroua <hbouaroua at freebox.fr>
Signed-off-by: James Almer <jamrial at gmail.com>
---
libavformat/avformat.h | 6 +++++
libavformat/isom.h | 1 +
libavformat/mov.c | 54 ++++++++++++++++++++++++++++++++++++++----
3 files changed, 57 insertions(+), 4 deletions(-)
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index 56c1c80289..a54aac0f3a 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -1082,6 +1082,12 @@ typedef struct AVStreamGroupTileGrid {
* final image before presentation.
*/
int height;
+
+ /**
+ * The angle in which the reconstructed image is rotated (in anti-clockwise
+ * direction) before presentation, in units of degrees.
+ */
+ AVRational rotation;
} AVStreamGroupTileGrid;
/**
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 4723397048..204addbab2 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -283,6 +283,7 @@ typedef struct HEIFItem {
int64_t extent_offset;
int width;
int height;
+ int rotation;
int type;
int is_idat_relative;
} HEIFItem;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index a2333ac1fd..480e6c81a5 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -40,6 +40,7 @@
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
+#include "libavutil/display.h"
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavutil/aes.h"
@@ -8929,6 +8930,27 @@ static int mov_read_ispe(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
+static int mov_read_irot(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+ int angle;
+
+ angle = avio_r8(pb) & 0x3;
+
+ av_log(c->fc, AV_LOG_TRACE, "irot: item_id %d, angle %u\n",
+ c->cur_item_id, angle);
+
+ for (int i = 0; i < c->nb_heif_item; i++) {
+ if (c->heif_item[i].item_id == c->cur_item_id) {
+ // angle * 90 specifies the angle (in anti-clockwise direction)
+ // in units of degrees.
+ c->heif_item[i].rotation = angle * 90;
+ break;
+ }
+ }
+
+ return 0;
+}
+
static int mov_read_iprp(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
typedef struct MOVAtoms {
@@ -9155,6 +9177,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
{ MKTAG('i','d','a','t'), mov_read_idat },
{ MKTAG('i','r','e','f'), mov_read_iref },
{ MKTAG('i','s','p','e'), mov_read_ispe },
+{ MKTAG('i','r','o','t'), mov_read_irot },
{ MKTAG('i','p','r','p'), mov_read_iprp },
{ MKTAG('i','i','n','f'), mov_read_iinf },
{ MKTAG('a','m','v','e'), mov_read_amve }, /* ambient viewing environment box */
@@ -9857,8 +9880,12 @@ static int read_image_grid(AVFormatContext *s, const HEIFGrid *grid,
tile_grid->width = (flags & 1) ? avio_rb32(s->pb) : avio_rb16(s->pb);
tile_grid->height = (flags & 1) ? avio_rb32(s->pb) : avio_rb16(s->pb);
- av_log(c->fc, AV_LOG_TRACE, "grid: grid_rows %d grid_cols %d output_width %d output_height %d\n",
- tile_rows, tile_cols, tile_grid->width, tile_grid->height);
+ /* rotation */
+ tile_grid->rotation = av_make_q(item->rotation, 1);
+
+ av_log(c->fc, AV_LOG_TRACE, "grid: grid_rows %d grid_cols %d output_width %d output_height %d "
+ "rotation %f\n",
+ tile_rows, tile_cols, tile_grid->width, tile_grid->height, av_q2d(tile_grid->rotation));
avio_seek(s->pb, pos, SEEK_SET);
@@ -9947,8 +9974,12 @@ static int read_image_iovl(AVFormatContext *s, const HEIFGrid *grid,
tile_grid->coded_width = (flags & 1) ? avio_rb32(s->pb) : avio_rb16(s->pb);
tile_grid->height =
tile_grid->coded_height = (flags & 1) ? avio_rb32(s->pb) : avio_rb16(s->pb);
- av_log(c->fc, AV_LOG_TRACE, "iovl: output_width %d, output_height %d\n",
- tile_grid->width, tile_grid->height);
+
+ /* rotation */
+ tile_grid->rotation = av_make_q(item->rotation, 1);
+
+ av_log(c->fc, AV_LOG_TRACE, "iovl: output_width %d, output_height %d, rotation %f\n",
+ tile_grid->width, tile_grid->height, av_q2d(tile_grid->rotation));
tile_grid->nb_tiles = grid->nb_tiles;
tile_grid->offsets = av_malloc_array(tile_grid->nb_tiles, sizeof(*tile_grid->offsets));
@@ -10149,6 +10180,21 @@ static int mov_read_header(AVFormatContext *s)
if (item->item_id == mov->primary_item_id)
st->disposition |= AV_DISPOSITION_DEFAULT;
+ if (item->rotation) {
+ int32_t *matrix;
+ AVPacketSideData *sd = av_packet_side_data_new(&st->codecpar->coded_side_data,
+ &st->codecpar->nb_coded_side_data,
+ AV_PKT_DATA_DISPLAYMATRIX,
+ 9 * sizeof(*matrix), 0);
+ if (!sd)
+ return AVERROR(ENOMEM);
+ matrix = (int32_t*)sd->data;
+
+ /* rotation is in the counter-clockwise direction whereas
+ * av_display_rotation_set() expects its argument to be
+ * oriented clockwise, so we need to negate it. */
+ av_display_rotation_set(matrix, -item->rotation);
+ }
mov_build_index(mov, st);
}
--
2.46.0
More information about the ffmpeg-devel
mailing list