Skip to content
This repository has been archived by the owner on Sep 16, 2023. It is now read-only.

Commit

Permalink
Revert "HDR: Remove unused code in FFmpegController"
Browse files Browse the repository at this point in the history
This reverts commit 4b5f0b9.
  • Loading branch information
CarterLi authored and low-batt committed Jan 21, 2022
1 parent dbc6205 commit e473a8d
Show file tree
Hide file tree
Showing 2 changed files with 177 additions and 0 deletions.
3 changes: 3 additions & 0 deletions iina/FFmpegController.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,7 @@

+ (nullable NSDictionary *)probeVideoInfoForFile:(nonnull NSString *)file;

// HDR
+ (nullable NSDictionary *)getColorSpaceMetadataForFile:(nonnull NSString *)file;

@end
174 changes: 174 additions & 0 deletions iina/FFmpegController.m
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,7 @@ - (int)getPeeksForFile:(NSString *)file
return 0;
}


- (void)saveThumbnail:(AVFrame *)pFrame width
:(int)width height
:(int)height index
Expand Down Expand Up @@ -330,6 +331,179 @@ - (void)saveThumbnail:(AVFrame *)pFrame width
}
}

// HDR
// Backward conversion from primaries metadata to color space is taken from here
// https://github.com/rigaya/NVEnc/issues/51#issuecomment-392572746
// Also from File__Analyze_Streams.cpp in MediaInfo

struct masteringdisplaycolorvolume_values
{
int Code; //ISO code
double Values[8]; // G, B, R, W pairs (x values then y values)
};
static const int MasteringDisplayColorVolume_Values_Size=4;
static const struct masteringdisplaycolorvolume_values MasteringDisplayColorVolume_Values[] =
{
{ 1, {15000, 30000, 7500, 3000, 32000, 16500, 15635, 16450}}, // BT.709
{ 9, { 8500, 39850, 6550, 2300, 35400, 14600, 15635, 16450}}, // BT.2020
{11, {13250, 34500, 7500, 3000, 34000, 16000, 15700, 17550}}, // DCI P3
{12, {13250 /*green_x*/, 34500 /*green_y*/, 7500 /*blue_x*/, 3000 /*blue_y*/, 34000 /*red_x*/, 16000 /*red_y*/, /* whitepoint_x */ 15635, /* whitepoint_y */ 16450}}, // Display P3
};

static inline double avr2d(AVRational a) {
return (double)a.num / (double)a.den;
}

+ (NSDictionary *)getColorSpaceMetadataForFile:(nonnull NSString *)file
{
int ret;
AVFormatContext *pFormatCtx = NULL;
AVCodecContext *pCodecCtx = NULL;
AVFrame *pFrame = NULL;

@try {
char *cFilename = strdup(file.fileSystemRepresentation);
ret = avformat_open_input(&pFormatCtx, cFilename, NULL, NULL);
free(cFilename);
if (ret < 0) return NULL;

ret = avformat_find_stream_info(pFormatCtx, NULL);
if (ret < 0) return NULL;

int videoStream = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (videoStream < 0) return NULL;

// Get the codec context for the video stream
AVStream *pVideoStream = pFormatCtx->streams[videoStream];

NSMutableDictionary *info = [[NSMutableDictionary alloc] init];

switch (pVideoStream->codecpar->color_trc)
{
// ITU-R BT.2100 HLG (Hybrid Log-gamma) curve, aka ARIB STD-B67
case AVCOL_TRC_ARIB_STD_B67: info[@"color-trc"] = @"hlg"; break;
// ITU-R BT.2100 PQ (Perceptual quantizer) curve, aka SMPTE ST2084
// assuming that AVCOL_TRC_SMPTEST2084 and AVCOL_TRC_SMPTE2084 have same value
case AVCOL_TRC_SMPTE2084: info[@"color-trc"] = @"pq"; break;

default: return NULL; // SDR content
}

AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)av_stream_get_side_data(pVideoStream, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, NULL);

if (!metadata) {
// Find the decoder for the video stream
AVCodec *pCodec = avcodec_find_decoder(pVideoStream->codecpar->codec_id);
if (!pCodec) return NULL;

// Open codec
pCodecCtx = avcodec_alloc_context3(pCodec);
if (!pCodecCtx) return NULL;

ret = avcodec_parameters_to_context(pCodecCtx, pVideoStream->codecpar);
if (ret < 0) return NULL;

ret = avcodec_open2(pCodecCtx, pCodec, NULL);
if (ret < 0) return NULL;

AVPacket packet;
while (av_read_frame(pFormatCtx, &packet) >= 0) {
if (packet.stream_index != videoStream) continue;
ret = avcodec_send_packet(pCodecCtx, &packet);
if (ret < 0) break;

metadata = (AVMasteringDisplayMetadata *)av_packet_get_side_data(&packet, AV_PKT_DATA_MASTERING_DISPLAY_METADATA, NULL);
if (metadata) break;

pFrame = av_frame_alloc();
ret = avcodec_receive_frame(pCodecCtx, pFrame);
if (ret < 0) {
if (ret == AVERROR(EAGAIN)) continue;
break;
}

AVFrameSideData* side_data = av_frame_get_side_data(pFrame, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA);

if(side_data) metadata = (AVMasteringDisplayMetadata *) side_data->data;
break;
}
}

if (metadata && metadata->has_primaries)
{
int code = -1;
for (int i=0; i<MasteringDisplayColorVolume_Values_Size; i++)
{
const struct masteringdisplaycolorvolume_values* values = &MasteringDisplayColorVolume_Values[i];
int j = 0;

// +/- 0.0005 (3 digits after comma)
double gValue = avr2d(metadata->display_primaries[1][0]) / 0.00002;
if (gValue<values->Values[0*2+j]-25 || gValue>=values->Values[0*2+j]+25)
continue;
double bValue = avr2d(metadata->display_primaries[2][0]) / 0.00002;
if (bValue<values->Values[1*2+j]-25 || bValue>=values->Values[1*2+j]+25)
continue;
double rValue = avr2d(metadata->display_primaries[0][0]) / 0.00002;
if (rValue<values->Values[2*2+j]-25 || rValue>=values->Values[2*2+j]+25)
continue;

// +/- 0.00005 (4 digits after comma)
double wpValue = avr2d(metadata->white_point[0]) / 0.00002;
if (wpValue<values->Values[3*2+j]-2 || wpValue>=values->Values[3*2+j]+3)
continue;

code = values->Code;
break;
}

switch (code)
{
case 9: info[@"primaries"] = @"bt.2020"; break;
case 11: info[@"primaries"] = @"dci-p3"; break;
case 12: info[@"primaries"] = @"display-p3"; break;

case 1: // bt709. The source may not be correctly encoded, ignoring...
default:
break;
}
}

if (!info[@"primaries"]) {
NSLog(@"HDR: Video source doesn't provide master display metadata");

switch (pVideoStream->codecpar->color_primaries) {
case AVCOL_PRI_SMPTE432: info[@"primaries"] = @"display-p3"; break;
case AVCOL_PRI_SMPTE431: info[@"primaries"] = @"dci-p3"; break;
case AVCOL_PRI_BT2020: default: info[@"primaries"] = @"bt.2020"; break;
}
}

if (metadata && metadata->has_luminance)
{
double max_luminance = avr2d(metadata->max_luminance);
info[@"max_luminance"] = [NSNumber numberWithDouble:max_luminance];
double min_luminance = avr2d(metadata->min_luminance);
info[@"min_luminance"] = [NSNumber numberWithDouble:min_luminance];
}

NSLog(@"HDR: primaries=%@ color-trc=%@ max_luminance=%@", info[@"primaries"], info[@"color-trc"], info[@"max_luminance"]);

return info;
} @finally {
if (pFrame) {
av_frame_free(&pFrame);
}
if (pCodecCtx) {
avcodec_free_context(&pCodecCtx);
}
if (pFormatCtx) {
avformat_close_input(&pFormatCtx);
avformat_free_context(pFormatCtx);
}
}
}

+ (NSDictionary *)probeVideoInfoForFile:(nonnull NSString *)file
{
int ret;
Expand Down

0 comments on commit e473a8d

Please sign in to comment.