/*****************************************************************************
* Ancillary.cpp: SDI Ancillary
*****************************************************************************
* Copyright © 2014-2016 VideoLAN and VideoLAN Authors
* 2018 VideoLabs
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "Ancillary.hpp"
#include "V210.hpp"
#include <cassert>
using namespace sdi;
static inline uint16_t withparitybit(uint16_t v)
{
return v | (vlc_parity(v) ? 0x100 : 0x200);
}
Ancillary::Data10bitPacket::Data10bitPacket(uint8_t did, uint8_t sdid,
const AbstractPacket<uint8_t> &other)
{
payload.reserve(6 + 1 + other.size());
payload.resize(6);
payload[0] = 0x000;
payload[1] = 0x3ff;
payload[2] = 0x3ff;
payload[3] = withparitybit(did);
payload[4] = withparitybit(sdid);
payload[5] = withparitybit(other.size());
for(std::size_t i = 0; i<other.size(); i++)
payload.push_back(withparitybit(other.data()[i]));
uint16_t sum = 0;
for(std::size_t i = 3; i<payload.size(); i++)
sum = (sum + payload[i]) & 0x1ff;
payload.push_back(sum | ((~sum & 0x100) << 1));
}
void Ancillary::Data10bitPacket::pad()
{
while(payload.size() % V210::ALIGNMENT_U16)
payload.push_back(0x40); /* padding */
}
AFD::AFD(uint8_t afdcode, uint8_t ar)
{
this->afdcode = afdcode;
this->ar = ar;
}
AFD::~AFD()
{
}
AFD::AFDData::AFDData(uint8_t code, uint8_t ar)
{
payload.resize(8);
int bar_data_flags = 0;
int bar_data_val1 = 0;
int bar_data_val2 = 0;
payload[0] = ((code & 0x0F) << 3) | ((ar & 0x01) << 2); /* SMPTE 2016-1 */
payload[1] = 0; // reserved
payload[2] = 0; // reserved
payload[3] = bar_data_flags << 4;
payload[4] = bar_data_val1 << 8;
payload[5] = bar_data_val1 & 0xff;
payload[6] = bar_data_val2 << 8;
payload[7] = bar_data_val2 & 0xff;
}
void AFD::FillBuffer(uint8_t *p_buf, size_t i_buf)
{
AFDData afd(afdcode, ar);
Data10bitPacket packet(0x41, 0x05, afd);
packet.pad();
if(packet.size() > i_buf)
return;
/* convert to v210 and write into VANC */
V210::Convert((uint16_t *)packet.data(), packet.size() / 2, p_buf);
}
Captions::CDP::CDP(const uint8_t * buf, std::size_t bufsize,
uint8_t rate, uint16_t cdp_counter)
{
std::size_t cc_count = bufsize / 3;
payload.reserve(9 + cc_count * 3 + 3 + 1);
payload.resize(9);
payload[0] = 0x96; // header id
payload[1] = 0x69;
payload[2] = 9 + 3 + 1 + cc_count * 3; // len
payload[3] = ((rate << 4) | 0x0f);
payload[4] = 0x43; // cc_data_present | caption_service_active | reserved
payload[5] = cdp_counter >> 8;
payload[6] = cdp_counter & 0xff;
payload[7] = 0x72; // ccdata_id
payload[8] = 0xe0 | cc_count; // cc_count
// cc data
for(std::size_t i=0; i<cc_count * 3; i++)
payload.push_back(buf[i]);
// cdp footer
payload.push_back(0x74); // footer id
payload.push_back(cdp_counter >> 8);
payload.push_back(cdp_counter & 0xff);
uint16_t sum = 0;
for(std::size_t i=0; i<payload.size(); i++)
sum = (sum + payload[i]) & 0xff;
payload.push_back(sum ? 256 - sum : sum); /* cdpsum */
}
Captions::Captions(const uint8_t *p, size_t s,
unsigned num, unsigned den)
{
cdp_counter = 0;
p_data = p;
i_data = s;
vlc_ureduce(&num, &den, num, den, 0);
if (num == 24000 && den == 1001) {
rate = 1;
} else if (num == 24 && den == 1) {
rate = 2;
} else if (num == 25 && den == 1) {
rate = 3;
} else if (num == 30000 && den == 1001) {
rate = 4;
} else if (num == 30 && den == 1) {
rate = 5;
} else if (num == 50 && den == 1) {
rate = 6;
} else if (num == 60000 && den == 1001) {
rate = 7;
} else if (num == 60 && den == 1) {
rate = 8;
} else {
rate = 1;
}
}
Captions::~Captions()
{
}
void Captions::FillBuffer(uint8_t *p_buf, size_t i_buf)
{
uint8_t cc_count = i_data / 3;
if (cc_count == 0)
return;
CDP cdp(p_data, i_data, rate, cdp_counter++);
Data10bitPacket packet(0x61, 0x01, cdp);
packet.pad();
if(packet.size() > i_buf)
return;
/* convert to v210 and write into VBI line 15 of VANC */
V210::Convert((uint16_t *)packet.data(), packet.size() / 2, p_buf);
}
¤ Dauer der Verarbeitung: 0.4 Sekunden
¤
*© Formatika GbR, Deutschland