2018-11-19 23:52:45 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Paul B Mahol
|
|
|
|
*
|
|
|
|
* This file is part of FFmpeg.
|
|
|
|
*
|
|
|
|
* FFmpeg is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* FFmpeg is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with FFmpeg; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
2024-04-10 15:17:54 +02:00
|
|
|
#include "bsf.h"
|
|
|
|
#include "bsf_internal.h"
|
|
|
|
#include "get_bits.h"
|
|
|
|
#include "mlp_parse.h"
|
|
|
|
#include "mlp.h"
|
2018-11-19 23:52:45 +02:00
|
|
|
|
|
|
|
typedef struct AccessUnit {
|
|
|
|
uint8_t bits[4];
|
|
|
|
uint16_t offset;
|
|
|
|
uint16_t optional;
|
|
|
|
} AccessUnit;
|
|
|
|
|
|
|
|
typedef struct TrueHDCoreContext {
|
|
|
|
MLPHeaderInfo hdr;
|
|
|
|
} TrueHDCoreContext;
|
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
static int truehd_core_filter(AVBSFContext *ctx, AVPacket *pkt)
|
2018-11-19 23:52:45 +02:00
|
|
|
{
|
|
|
|
TrueHDCoreContext *s = ctx->priv_data;
|
|
|
|
GetBitContext gbc;
|
|
|
|
AccessUnit units[MAX_SUBSTREAMS];
|
truehd_core: Miscellaneous improvements
1. The loop counter of the substream_directory loop is always less than
the number of substreams, yet within the loop it is checked whether it
is less than FFMIN(3, s->hdr.num_substreams), although the check for < 3
would suffice.
2. In case the packet is a major sync packet, the last two bytes of the
major sync structure were initialized to 0xff and then immediately
overwritten afterwards without ever making use of the values just set.
3. When updating the parity_nibble during writing the new
substream_directory, the parity_nibble is updated one byte at a time
with bytes that might be read from the output packet's data. But one can
do both bytes at the same time without resorting to the data just
written by XOR'ing with the variable that contains the value that has
just been written as a big endian number. This changes the intermediate
value of parity_nibble, but in the end it just amounts to a reordering
of the sum modulo two that will eventually be written as parity_nibble.
Due to associativity and commutativity, this value is unchanged.
4. init_get_bits8 already checks that no overflow happens during the
conversion of its argument from bytes to bits. ff_mlp_read_major_sync
makes sure not to overread (the maximum size of a major_sync_info is 60
bytes anyway) and last_offset is < 2^13, so that no overflow in the
calculation of size can happen, i.e. the check for whether size is >= 0
is unnecessary. But then size is completely unnecessary and can be
removed.
5. In case the packet is just passed through, it is unnecessary to read
the packet's dts. This is therefore postponed to when we know that the
packet is not passed through.
6. Given that it seems overkill to use a bitreader just for one
variable, the size of the input access unit is now read directly.
7. A substream's offset (of the end of the substream) is now stored as is
(i.e. in units of words).
These changes amount to a slight performance improvement: It improved
from 5897 decicycles of ten runs with about 262144 runs each (including
an insignificant amount -- about 20-25 usually of skips) to 5747
decicycles under the same conditions.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2019-07-06 16:18:02 +02:00
|
|
|
int ret, i, last_offset = 0;
|
2018-11-19 23:52:45 +02:00
|
|
|
int in_size, out_size;
|
|
|
|
int have_header = 0;
|
2019-07-06 16:18:03 +02:00
|
|
|
int substream_bytes = 0;
|
2019-07-06 16:18:00 +02:00
|
|
|
int end;
|
2018-11-19 23:52:45 +02:00
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
ret = ff_bsf_get_packet_ref(ctx, pkt);
|
2018-11-19 23:52:45 +02:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
if (pkt->size < 4) {
|
2019-07-06 16:18:01 +02:00
|
|
|
ret = AVERROR_INVALIDDATA;
|
2018-11-19 23:52:45 +02:00
|
|
|
goto fail;
|
2019-07-06 16:18:01 +02:00
|
|
|
}
|
2018-11-19 23:52:45 +02:00
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
in_size = (AV_RB16(pkt->data) & 0xFFF) * 2;
|
|
|
|
if (in_size < 4 || in_size > pkt->size) {
|
2019-07-06 16:18:01 +02:00
|
|
|
ret = AVERROR_INVALIDDATA;
|
2018-11-19 23:52:45 +02:00
|
|
|
goto fail;
|
2019-07-06 16:18:01 +02:00
|
|
|
}
|
2018-11-19 23:52:45 +02:00
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
ret = init_get_bits8(&gbc, pkt->data + 4, pkt->size - 4);
|
2018-11-19 23:52:45 +02:00
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
if (show_bits_long(&gbc, 32) == 0xf8726fba) {
|
2019-07-06 16:18:01 +02:00
|
|
|
if ((ret = ff_mlp_read_major_sync(ctx, &s->hdr, &gbc)) < 0)
|
2018-11-19 23:52:45 +02:00
|
|
|
goto fail;
|
|
|
|
have_header = 1;
|
|
|
|
}
|
|
|
|
|
2019-07-06 16:18:01 +02:00
|
|
|
if (s->hdr.num_substreams > MAX_SUBSTREAMS) {
|
|
|
|
ret = AVERROR_INVALIDDATA;
|
2018-11-19 23:52:45 +02:00
|
|
|
goto fail;
|
2019-07-06 16:18:01 +02:00
|
|
|
}
|
2018-11-19 23:52:45 +02:00
|
|
|
|
|
|
|
for (i = 0; i < s->hdr.num_substreams; i++) {
|
|
|
|
for (int j = 0; j < 4; j++)
|
|
|
|
units[i].bits[j] = get_bits1(&gbc);
|
|
|
|
|
truehd_core: Miscellaneous improvements
1. The loop counter of the substream_directory loop is always less than
the number of substreams, yet within the loop it is checked whether it
is less than FFMIN(3, s->hdr.num_substreams), although the check for < 3
would suffice.
2. In case the packet is a major sync packet, the last two bytes of the
major sync structure were initialized to 0xff and then immediately
overwritten afterwards without ever making use of the values just set.
3. When updating the parity_nibble during writing the new
substream_directory, the parity_nibble is updated one byte at a time
with bytes that might be read from the output packet's data. But one can
do both bytes at the same time without resorting to the data just
written by XOR'ing with the variable that contains the value that has
just been written as a big endian number. This changes the intermediate
value of parity_nibble, but in the end it just amounts to a reordering
of the sum modulo two that will eventually be written as parity_nibble.
Due to associativity and commutativity, this value is unchanged.
4. init_get_bits8 already checks that no overflow happens during the
conversion of its argument from bytes to bits. ff_mlp_read_major_sync
makes sure not to overread (the maximum size of a major_sync_info is 60
bytes anyway) and last_offset is < 2^13, so that no overflow in the
calculation of size can happen, i.e. the check for whether size is >= 0
is unnecessary. But then size is completely unnecessary and can be
removed.
5. In case the packet is just passed through, it is unnecessary to read
the packet's dts. This is therefore postponed to when we know that the
packet is not passed through.
6. Given that it seems overkill to use a bitreader just for one
variable, the size of the input access unit is now read directly.
7. A substream's offset (of the end of the substream) is now stored as is
(i.e. in units of words).
These changes amount to a slight performance improvement: It improved
from 5897 decicycles of ten runs with about 262144 runs each (including
an insignificant amount -- about 20-25 usually of skips) to 5747
decicycles under the same conditions.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2019-07-06 16:18:02 +02:00
|
|
|
units[i].offset = get_bits(&gbc, 12);
|
|
|
|
if (i < 3) {
|
|
|
|
last_offset = units[i].offset * 2;
|
2019-07-06 16:18:03 +02:00
|
|
|
substream_bytes += 2;
|
2018-11-19 23:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (units[i].bits[0]) {
|
|
|
|
units[i].optional = get_bits(&gbc, 16);
|
truehd_core: Miscellaneous improvements
1. The loop counter of the substream_directory loop is always less than
the number of substreams, yet within the loop it is checked whether it
is less than FFMIN(3, s->hdr.num_substreams), although the check for < 3
would suffice.
2. In case the packet is a major sync packet, the last two bytes of the
major sync structure were initialized to 0xff and then immediately
overwritten afterwards without ever making use of the values just set.
3. When updating the parity_nibble during writing the new
substream_directory, the parity_nibble is updated one byte at a time
with bytes that might be read from the output packet's data. But one can
do both bytes at the same time without resorting to the data just
written by XOR'ing with the variable that contains the value that has
just been written as a big endian number. This changes the intermediate
value of parity_nibble, but in the end it just amounts to a reordering
of the sum modulo two that will eventually be written as parity_nibble.
Due to associativity and commutativity, this value is unchanged.
4. init_get_bits8 already checks that no overflow happens during the
conversion of its argument from bytes to bits. ff_mlp_read_major_sync
makes sure not to overread (the maximum size of a major_sync_info is 60
bytes anyway) and last_offset is < 2^13, so that no overflow in the
calculation of size can happen, i.e. the check for whether size is >= 0
is unnecessary. But then size is completely unnecessary and can be
removed.
5. In case the packet is just passed through, it is unnecessary to read
the packet's dts. This is therefore postponed to when we know that the
packet is not passed through.
6. Given that it seems overkill to use a bitreader just for one
variable, the size of the input access unit is now read directly.
7. A substream's offset (of the end of the substream) is now stored as is
(i.e. in units of words).
These changes amount to a slight performance improvement: It improved
from 5897 decicycles of ten runs with about 262144 runs each (including
an insignificant amount -- about 20-25 usually of skips) to 5747
decicycles under the same conditions.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2019-07-06 16:18:02 +02:00
|
|
|
if (i < 3)
|
2019-07-06 16:18:03 +02:00
|
|
|
substream_bytes += 2;
|
2018-11-19 23:52:45 +02:00
|
|
|
}
|
|
|
|
}
|
2019-07-06 16:18:03 +02:00
|
|
|
end = get_bits_count(&gbc) >> 3;
|
2018-11-19 23:52:45 +02:00
|
|
|
|
2019-07-06 16:18:03 +02:00
|
|
|
out_size = end + 4 + last_offset;
|
2018-11-19 23:52:45 +02:00
|
|
|
if (out_size < in_size) {
|
2019-07-06 16:18:03 +02:00
|
|
|
int bpos = 0, reduce = end - have_header * 28 - substream_bytes;
|
2019-07-06 16:18:04 +02:00
|
|
|
uint16_t parity_nibble, dts = AV_RB16(pkt->data + 2);
|
2018-11-19 23:52:45 +02:00
|
|
|
uint16_t auheader;
|
2019-07-06 16:18:04 +02:00
|
|
|
uint8_t header[28];
|
2018-11-19 23:52:45 +02:00
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
av_assert1(reduce >= 0 && reduce % 2 == 0);
|
2019-07-06 16:18:03 +02:00
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
if (have_header) {
|
|
|
|
memcpy(header, pkt->data + 4, 28);
|
|
|
|
header[16] = (header[16] & 0x0c) | (FFMIN(s->hdr.num_substreams, 3) << 4);
|
|
|
|
header[17] &= 0x7f;
|
|
|
|
header[25] &= 0xfe;
|
|
|
|
AV_WL16(header + 26, ff_mlp_checksum16(header, 26));
|
|
|
|
}
|
|
|
|
|
|
|
|
pkt->data += reduce;
|
|
|
|
out_size -= reduce;
|
|
|
|
pkt->size = out_size;
|
|
|
|
|
|
|
|
ret = av_packet_make_writable(pkt);
|
2018-11-19 23:52:45 +02:00
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
AV_WB16(pkt->data + 2, dts);
|
2018-11-19 23:52:45 +02:00
|
|
|
parity_nibble = dts;
|
2019-07-06 16:18:04 +02:00
|
|
|
parity_nibble ^= out_size / 2;
|
2018-11-19 23:52:45 +02:00
|
|
|
|
|
|
|
for (i = 0; i < FFMIN(s->hdr.num_substreams, 3); i++) {
|
|
|
|
uint16_t substr_hdr = 0;
|
|
|
|
|
|
|
|
substr_hdr |= (units[i].bits[0] << 15);
|
|
|
|
substr_hdr |= (units[i].bits[1] << 14);
|
|
|
|
substr_hdr |= (units[i].bits[2] << 13);
|
|
|
|
substr_hdr |= (units[i].bits[3] << 12);
|
truehd_core: Miscellaneous improvements
1. The loop counter of the substream_directory loop is always less than
the number of substreams, yet within the loop it is checked whether it
is less than FFMIN(3, s->hdr.num_substreams), although the check for < 3
would suffice.
2. In case the packet is a major sync packet, the last two bytes of the
major sync structure were initialized to 0xff and then immediately
overwritten afterwards without ever making use of the values just set.
3. When updating the parity_nibble during writing the new
substream_directory, the parity_nibble is updated one byte at a time
with bytes that might be read from the output packet's data. But one can
do both bytes at the same time without resorting to the data just
written by XOR'ing with the variable that contains the value that has
just been written as a big endian number. This changes the intermediate
value of parity_nibble, but in the end it just amounts to a reordering
of the sum modulo two that will eventually be written as parity_nibble.
Due to associativity and commutativity, this value is unchanged.
4. init_get_bits8 already checks that no overflow happens during the
conversion of its argument from bytes to bits. ff_mlp_read_major_sync
makes sure not to overread (the maximum size of a major_sync_info is 60
bytes anyway) and last_offset is < 2^13, so that no overflow in the
calculation of size can happen, i.e. the check for whether size is >= 0
is unnecessary. But then size is completely unnecessary and can be
removed.
5. In case the packet is just passed through, it is unnecessary to read
the packet's dts. This is therefore postponed to when we know that the
packet is not passed through.
6. Given that it seems overkill to use a bitreader just for one
variable, the size of the input access unit is now read directly.
7. A substream's offset (of the end of the substream) is now stored as is
(i.e. in units of words).
These changes amount to a slight performance improvement: It improved
from 5897 decicycles of ten runs with about 262144 runs each (including
an insignificant amount -- about 20-25 usually of skips) to 5747
decicycles under the same conditions.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2019-07-06 16:18:02 +02:00
|
|
|
substr_hdr |= units[i].offset;
|
2018-11-19 23:52:45 +02:00
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
AV_WB16(pkt->data + have_header * 28 + 4 + bpos, substr_hdr);
|
2018-11-19 23:52:45 +02:00
|
|
|
|
truehd_core: Miscellaneous improvements
1. The loop counter of the substream_directory loop is always less than
the number of substreams, yet within the loop it is checked whether it
is less than FFMIN(3, s->hdr.num_substreams), although the check for < 3
would suffice.
2. In case the packet is a major sync packet, the last two bytes of the
major sync structure were initialized to 0xff and then immediately
overwritten afterwards without ever making use of the values just set.
3. When updating the parity_nibble during writing the new
substream_directory, the parity_nibble is updated one byte at a time
with bytes that might be read from the output packet's data. But one can
do both bytes at the same time without resorting to the data just
written by XOR'ing with the variable that contains the value that has
just been written as a big endian number. This changes the intermediate
value of parity_nibble, but in the end it just amounts to a reordering
of the sum modulo two that will eventually be written as parity_nibble.
Due to associativity and commutativity, this value is unchanged.
4. init_get_bits8 already checks that no overflow happens during the
conversion of its argument from bytes to bits. ff_mlp_read_major_sync
makes sure not to overread (the maximum size of a major_sync_info is 60
bytes anyway) and last_offset is < 2^13, so that no overflow in the
calculation of size can happen, i.e. the check for whether size is >= 0
is unnecessary. But then size is completely unnecessary and can be
removed.
5. In case the packet is just passed through, it is unnecessary to read
the packet's dts. This is therefore postponed to when we know that the
packet is not passed through.
6. Given that it seems overkill to use a bitreader just for one
variable, the size of the input access unit is now read directly.
7. A substream's offset (of the end of the substream) is now stored as is
(i.e. in units of words).
These changes amount to a slight performance improvement: It improved
from 5897 decicycles of ten runs with about 262144 runs each (including
an insignificant amount -- about 20-25 usually of skips) to 5747
decicycles under the same conditions.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2019-07-06 16:18:02 +02:00
|
|
|
parity_nibble ^= substr_hdr;
|
|
|
|
bpos += 2;
|
2018-11-19 23:52:45 +02:00
|
|
|
|
|
|
|
if (units[i].bits[0]) {
|
2019-07-06 16:18:04 +02:00
|
|
|
AV_WB16(pkt->data + have_header * 28 + 4 + bpos, units[i].optional);
|
2018-11-19 23:52:45 +02:00
|
|
|
|
truehd_core: Miscellaneous improvements
1. The loop counter of the substream_directory loop is always less than
the number of substreams, yet within the loop it is checked whether it
is less than FFMIN(3, s->hdr.num_substreams), although the check for < 3
would suffice.
2. In case the packet is a major sync packet, the last two bytes of the
major sync structure were initialized to 0xff and then immediately
overwritten afterwards without ever making use of the values just set.
3. When updating the parity_nibble during writing the new
substream_directory, the parity_nibble is updated one byte at a time
with bytes that might be read from the output packet's data. But one can
do both bytes at the same time without resorting to the data just
written by XOR'ing with the variable that contains the value that has
just been written as a big endian number. This changes the intermediate
value of parity_nibble, but in the end it just amounts to a reordering
of the sum modulo two that will eventually be written as parity_nibble.
Due to associativity and commutativity, this value is unchanged.
4. init_get_bits8 already checks that no overflow happens during the
conversion of its argument from bytes to bits. ff_mlp_read_major_sync
makes sure not to overread (the maximum size of a major_sync_info is 60
bytes anyway) and last_offset is < 2^13, so that no overflow in the
calculation of size can happen, i.e. the check for whether size is >= 0
is unnecessary. But then size is completely unnecessary and can be
removed.
5. In case the packet is just passed through, it is unnecessary to read
the packet's dts. This is therefore postponed to when we know that the
packet is not passed through.
6. Given that it seems overkill to use a bitreader just for one
variable, the size of the input access unit is now read directly.
7. A substream's offset (of the end of the substream) is now stored as is
(i.e. in units of words).
These changes amount to a slight performance improvement: It improved
from 5897 decicycles of ten runs with about 262144 runs each (including
an insignificant amount -- about 20-25 usually of skips) to 5747
decicycles under the same conditions.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
2019-07-06 16:18:02 +02:00
|
|
|
parity_nibble ^= units[i].optional;
|
|
|
|
bpos += 2;
|
2018-11-19 23:52:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
parity_nibble ^= parity_nibble >> 8;
|
|
|
|
parity_nibble ^= parity_nibble >> 4;
|
|
|
|
parity_nibble &= 0xF;
|
|
|
|
|
|
|
|
auheader = (parity_nibble ^ 0xF) << 12;
|
2019-07-06 16:18:04 +02:00
|
|
|
auheader |= (out_size / 2) & 0x0fff;
|
|
|
|
AV_WB16(pkt->data, auheader);
|
2018-11-19 23:52:45 +02:00
|
|
|
|
2019-07-06 16:18:04 +02:00
|
|
|
if (have_header)
|
|
|
|
memcpy(pkt->data + 4, header, 28);
|
2018-11-19 23:52:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (ret < 0)
|
2019-07-06 16:18:04 +02:00
|
|
|
av_packet_unref(pkt);
|
2018-11-19 23:52:45 +02:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-05-05 03:10:40 +02:00
|
|
|
static void truehd_core_flush(AVBSFContext *ctx)
|
|
|
|
{
|
|
|
|
TrueHDCoreContext *s = ctx->priv_data;
|
|
|
|
memset(&s->hdr, 0, sizeof(s->hdr));
|
|
|
|
}
|
|
|
|
|
2018-11-19 23:52:45 +02:00
|
|
|
static const enum AVCodecID codec_ids[] = {
|
|
|
|
AV_CODEC_ID_TRUEHD, AV_CODEC_ID_NONE,
|
|
|
|
};
|
|
|
|
|
2022-03-21 23:25:27 +02:00
|
|
|
const FFBitStreamFilter ff_truehd_core_bsf = {
|
|
|
|
.p.name = "truehd_core",
|
|
|
|
.p.codec_ids = codec_ids,
|
2018-11-19 23:52:45 +02:00
|
|
|
.priv_data_size = sizeof(TrueHDCoreContext),
|
|
|
|
.filter = truehd_core_filter,
|
2019-05-05 03:10:40 +02:00
|
|
|
.flush = truehd_core_flush,
|
2018-11-19 23:52:45 +02:00
|
|
|
};
|