You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-15 14:13:16 +02:00
avformat/movenc: write channel descriptions when a known layout or a bitmap can't be used
Fixes part of ticket #2865 Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
@@ -504,9 +504,29 @@ static uint64_t mov_get_channel_mask(uint32_t label)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
|
static uint32_t mov_get_channel_label(enum AVChannel channel)
|
||||||
const AVChannelLayout *ch_layout,
|
{
|
||||||
uint32_t *bitmap)
|
if (channel < 0)
|
||||||
|
return 0;
|
||||||
|
if (channel <= AV_CHAN_TOP_BACK_RIGHT)
|
||||||
|
return channel + 1;
|
||||||
|
if (channel == AV_CHAN_WIDE_LEFT)
|
||||||
|
return 35;
|
||||||
|
if (channel == AV_CHAN_WIDE_RIGHT)
|
||||||
|
return 36;
|
||||||
|
if (channel == AV_CHAN_LOW_FREQUENCY_2)
|
||||||
|
return 37;
|
||||||
|
if (channel == AV_CHAN_STEREO_LEFT)
|
||||||
|
return 38;
|
||||||
|
if (channel == AV_CHAN_STEREO_RIGHT)
|
||||||
|
return 39;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ff_mov_get_channel_layout_tag(const AVCodecParameters *par,
|
||||||
|
uint32_t *layout,
|
||||||
|
uint32_t *bitmap,
|
||||||
|
uint32_t **pchannel_desc)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
uint32_t tag = 0;
|
uint32_t tag = 0;
|
||||||
@@ -514,7 +534,7 @@ uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
|
|||||||
|
|
||||||
/* find the layout list for the specified codec */
|
/* find the layout list for the specified codec */
|
||||||
for (i = 0; mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE; i++) {
|
for (i = 0; mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE; i++) {
|
||||||
if (mov_codec_ch_layouts[i].codec_id == codec_id)
|
if (mov_codec_ch_layouts[i].codec_id == par->codec_id)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE)
|
if (mov_codec_ch_layouts[i].codec_id != AV_CODEC_ID_NONE)
|
||||||
@@ -525,7 +545,7 @@ uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
|
|||||||
const struct MovChannelLayoutMap *layout_map;
|
const struct MovChannelLayoutMap *layout_map;
|
||||||
|
|
||||||
/* get the layout map based on the channel count */
|
/* get the layout map based on the channel count */
|
||||||
channels = ch_layout->nb_channels;
|
channels = par->ch_layout.nb_channels;
|
||||||
if (channels > 9)
|
if (channels > 9)
|
||||||
channels = 0;
|
channels = 0;
|
||||||
layout_map = mov_ch_layout_map[channels];
|
layout_map = mov_ch_layout_map[channels];
|
||||||
@@ -536,8 +556,8 @@ uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
|
|||||||
continue;
|
continue;
|
||||||
for (j = 0; layout_map[j].tag != 0; j++) {
|
for (j = 0; layout_map[j].tag != 0; j++) {
|
||||||
if (layout_map[j].tag == layouts[i] &&
|
if (layout_map[j].tag == layouts[i] &&
|
||||||
(ch_layout->order == AV_CHANNEL_ORDER_NATIVE &&
|
(par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE &&
|
||||||
layout_map[j].layout == ch_layout->u.mask))
|
layout_map[j].layout == par->ch_layout.u.mask))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (layout_map[j].tag)
|
if (layout_map[j].tag)
|
||||||
@@ -546,18 +566,39 @@ uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
|
|||||||
tag = layouts[i];
|
tag = layouts[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if no tag was found, use channel bitmap as a backup if possible */
|
*layout = tag;
|
||||||
if (tag == 0 && av_channel_layout_check(ch_layout) &&
|
|
||||||
ch_layout->order == AV_CHANNEL_ORDER_NATIVE &&
|
|
||||||
ch_layout->u.mask < 0x40000) {
|
|
||||||
tag = MOV_CH_LAYOUT_USE_BITMAP;
|
|
||||||
*bitmap = (uint32_t)ch_layout->u.mask;
|
|
||||||
} else
|
|
||||||
*bitmap = 0;
|
*bitmap = 0;
|
||||||
|
*pchannel_desc = NULL;
|
||||||
|
|
||||||
/* TODO: set channel descriptions as a secondary backup */
|
/* if no tag was found, use channel bitmap or description as a backup if possible */
|
||||||
|
if (tag == 0) {
|
||||||
|
uint32_t *channel_desc;
|
||||||
|
if (par->ch_layout.order == AV_CHANNEL_ORDER_NATIVE &&
|
||||||
|
par->ch_layout.u.mask < 0x40000) {
|
||||||
|
*layout = MOV_CH_LAYOUT_USE_BITMAP;
|
||||||
|
*bitmap = (uint32_t)par->ch_layout.u.mask;
|
||||||
|
return 0;
|
||||||
|
} else if (par->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC)
|
||||||
|
return AVERROR(ENOSYS);
|
||||||
|
|
||||||
return tag;
|
channel_desc = av_malloc_array(par->ch_layout.nb_channels, sizeof(*channel_desc));
|
||||||
|
if (!channel_desc)
|
||||||
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
for (i = 0; i < par->ch_layout.nb_channels; i++) {
|
||||||
|
channel_desc[i] =
|
||||||
|
mov_get_channel_label(av_channel_layout_channel_from_index(&par->ch_layout, i));
|
||||||
|
|
||||||
|
if (channel_desc[i] == 0) {
|
||||||
|
av_free(channel_desc);
|
||||||
|
return AVERROR(ENOSYS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pchannel_desc = channel_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st,
|
int ff_mov_read_chan(AVFormatContext *s, AVIOContext *pb, AVStream *st,
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "libavutil/channel_layout.h"
|
#include "libavutil/channel_layout.h"
|
||||||
#include "libavcodec/codec_id.h"
|
#include "libavcodec/codec_id.h"
|
||||||
|
#include "libavcodec/codec_par.h"
|
||||||
#include "avformat.h"
|
#include "avformat.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,9 +42,10 @@
|
|||||||
* @param[out] bitmap channel bitmap
|
* @param[out] bitmap channel bitmap
|
||||||
* @return channel layout tag
|
* @return channel layout tag
|
||||||
*/
|
*/
|
||||||
uint32_t ff_mov_get_channel_layout_tag(enum AVCodecID codec_id,
|
int ff_mov_get_channel_layout_tag(const AVCodecParameters *par,
|
||||||
const AVChannelLayout *ch_layout,
|
uint32_t *layout,
|
||||||
uint32_t *bitmap);
|
uint32_t *bitmap,
|
||||||
|
uint32_t **pchannel_desc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read 'chan' tag from the input stream.
|
* Read 'chan' tag from the input stream.
|
||||||
|
@@ -867,28 +867,45 @@ static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra
|
|||||||
|
|
||||||
static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
|
static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
|
||||||
{
|
{
|
||||||
uint32_t layout_tag, bitmap;
|
uint32_t layout_tag, bitmap, *channel_desc;
|
||||||
int64_t pos = avio_tell(pb);
|
int64_t pos = avio_tell(pb);
|
||||||
|
int num_desc, ret;
|
||||||
layout_tag = ff_mov_get_channel_layout_tag(track->par->codec_id,
|
|
||||||
&track->par->ch_layout,
|
|
||||||
&bitmap);
|
|
||||||
if (!layout_tag) {
|
|
||||||
av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
|
|
||||||
"lack of channel information\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (track->multichannel_as_mono)
|
if (track->multichannel_as_mono)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
|
||||||
|
&bitmap, &channel_desc);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
if (ret == AVERROR(ENOSYS)) {
|
||||||
|
av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
|
||||||
|
"lack of channel information\n");
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
|
||||||
|
|
||||||
avio_wb32(pb, 0); // Size
|
avio_wb32(pb, 0); // Size
|
||||||
ffio_wfourcc(pb, "chan"); // Type
|
ffio_wfourcc(pb, "chan"); // Type
|
||||||
avio_w8(pb, 0); // Version
|
avio_w8(pb, 0); // Version
|
||||||
avio_wb24(pb, 0); // Flags
|
avio_wb24(pb, 0); // Flags
|
||||||
avio_wb32(pb, layout_tag); // mChannelLayoutTag
|
avio_wb32(pb, layout_tag); // mChannelLayoutTag
|
||||||
avio_wb32(pb, bitmap); // mChannelBitmap
|
avio_wb32(pb, bitmap); // mChannelBitmap
|
||||||
avio_wb32(pb, 0); // mNumberChannelDescriptions
|
avio_wb32(pb, num_desc); // mNumberChannelDescriptions
|
||||||
|
|
||||||
|
for (int i = 0; i < num_desc; i++) {
|
||||||
|
avio_wb32(pb, channel_desc[i]); // mChannelLabel
|
||||||
|
avio_wb32(pb, 0); // mChannelFlags
|
||||||
|
avio_wl32(pb, 0); // mCoordinates[0]
|
||||||
|
avio_wl32(pb, 0); // mCoordinates[1]
|
||||||
|
avio_wl32(pb, 0); // mCoordinates[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
av_free(channel_desc);
|
||||||
|
|
||||||
return update_size(pb, pos);
|
return update_size(pb, pos);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user