@@ -425,34 +425,13 @@ FootageDescription FFmpegDecoder::Probe(const QString &filename, const QAtomicIn
|
||||
Instance instance;
|
||||
instance.Open(filename_c, avstream->index);
|
||||
|
||||
//qDebug() << instance.GetSubtitleHeader();
|
||||
while (instance.GetPacket(pkt) >= 0) {
|
||||
TimeRange time(Timecode::timestamp_to_time(pkt->pts, avstream->time_base),
|
||||
Timecode::timestamp_to_time(pkt->pts + pkt->duration, avstream->time_base));
|
||||
|
||||
AVSubtitle avsub;
|
||||
while (instance.GetSubtitle(pkt, &avsub) >= 0) {
|
||||
for (unsigned int j=0; j<avsub.num_rects; j++) {
|
||||
QString ass = avsub.rects[j]->ass;
|
||||
QString text = QString::fromUtf8((const char *) pkt->data, pkt->size);
|
||||
|
||||
int comma = 0;
|
||||
for (int k=0; k<ass.size(); k++) {
|
||||
if (ass.at(k) == ',') {
|
||||
comma++;
|
||||
}
|
||||
|
||||
// HARDCODED: I think FFmpeg always puts the text of SRTs in the 8th section
|
||||
if (comma == 8) {
|
||||
ass = ass.mid(k+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ass.replace(QStringLiteral("\\n"), QStringLiteral("\n"), Qt::CaseInsensitive);
|
||||
|
||||
TimeRange time(Timecode::timestamp_to_time(pkt->pts, avstream->time_base),
|
||||
Timecode::timestamp_to_time(pkt->pts + pkt->duration, avstream->time_base));
|
||||
|
||||
sub.push_back(Subtitle(time, ass));
|
||||
}
|
||||
avsubtitle_free(&avsub);
|
||||
sub.push_back(Subtitle(time, text));
|
||||
}
|
||||
|
||||
instance.Close();
|
||||
@@ -1132,13 +1111,7 @@ int FFmpegDecoder::Instance::GetFrame(AVPacket *pkt, AVFrame *frame)
|
||||
while ((ret = avcodec_receive_frame(codec_ctx_, frame)) == AVERROR(EAGAIN) && !eof) {
|
||||
|
||||
// Find next packet in the correct stream index
|
||||
do {
|
||||
// Free buffer in packet if there is one
|
||||
av_packet_unref(pkt);
|
||||
|
||||
// Read packet from file
|
||||
ret = av_read_frame(fmt_ctx_, pkt);
|
||||
} while (pkt->stream_index != avstream_->index && ret >= 0);
|
||||
ret = GetPacket(pkt);
|
||||
|
||||
if (ret == AVERROR_EOF) {
|
||||
// Don't break so that receive gets called again, but don't try to read again
|
||||
@@ -1172,13 +1145,7 @@ const char *FFmpegDecoder::Instance::GetSubtitleHeader() const
|
||||
|
||||
int FFmpegDecoder::Instance::GetSubtitle(AVPacket *pkt, AVSubtitle *sub)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
av_packet_unref(pkt);
|
||||
|
||||
ret = av_read_frame(fmt_ctx_, pkt);
|
||||
} while (pkt->stream_index != avstream_->index && ret >= 0);
|
||||
int ret = GetPacket(pkt);
|
||||
|
||||
if (ret >= 0) {
|
||||
int got_sub;
|
||||
@@ -1191,6 +1158,19 @@ int FFmpegDecoder::Instance::GetSubtitle(AVPacket *pkt, AVSubtitle *sub)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int FFmpegDecoder::Instance::GetPacket(AVPacket *pkt)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
av_packet_unref(pkt);
|
||||
|
||||
ret = av_read_frame(fmt_ctx_, pkt);
|
||||
} while (pkt->stream_index != avstream_->index && ret >= 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FFmpegDecoder::Instance::Seek(int64_t timestamp)
|
||||
{
|
||||
avcodec_flush_buffers(codec_ctx_);
|
||||
|
||||
@@ -95,6 +95,8 @@ private:
|
||||
|
||||
int GetSubtitle(AVPacket* pkt, AVSubtitle* sub);
|
||||
|
||||
int GetPacket(AVPacket *pkt);
|
||||
|
||||
void Seek(int64_t timestamp);
|
||||
|
||||
AVFormatContext* fmt_ctx() const
|
||||
|
||||
@@ -376,46 +376,15 @@ QString GetAssTime(const rational &time)
|
||||
|
||||
bool FFmpegEncoder::WriteSubtitle(const SubtitleBlock *sub_block)
|
||||
{
|
||||
AVSubtitle subtitle;
|
||||
memset(&subtitle, 0, sizeof(subtitle));
|
||||
|
||||
AVSubtitleRect rect;
|
||||
memset(&rect, 0, sizeof(rect));
|
||||
|
||||
QString ass_line = QStringLiteral("Dialogue: 0,%1,%2,Default,,0,0,0,,%3").arg(
|
||||
GetAssTime(sub_block->in()),
|
||||
GetAssTime(sub_block->out()),
|
||||
sub_block->GetText()
|
||||
);
|
||||
|
||||
QByteArray utf8_sub = sub_block->GetText().toUtf8();
|
||||
QByteArray utf8_ass = ass_line.toUtf8();
|
||||
|
||||
rect.type = SUBTITLE_ASS;
|
||||
rect.text = utf8_sub.data();
|
||||
rect.ass = utf8_ass.data();
|
||||
|
||||
AVSubtitleRect *rect_array = ▭
|
||||
subtitle.num_rects = 1;
|
||||
subtitle.rects = &rect_array;
|
||||
|
||||
subtitle.pts = Timecode::time_to_timestamp(sub_block->in(), subtitle_codec_ctx_->time_base, Timecode::kFloor);
|
||||
subtitle.end_display_time = qRound64(sub_block->length().toDouble() * 1000);
|
||||
|
||||
QVector<uint8_t> out_buf(1024 * 1024);
|
||||
|
||||
int sub_sz = avcodec_encode_subtitle(subtitle_codec_ctx_, out_buf.data(), out_buf.size(), &subtitle);
|
||||
if (sub_sz < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AVPacket *pkt = av_packet_alloc();
|
||||
|
||||
pkt->stream_index = subtitle_stream_->index;
|
||||
pkt->data = out_buf.data();
|
||||
pkt->size = sub_sz;
|
||||
pkt->pts = subtitle.pts;
|
||||
pkt->duration = av_rescale_q(subtitle.end_display_time, {1, 1000}, subtitle_codec_ctx_->time_base);
|
||||
pkt->data = (uint8_t *) utf8_sub.data();
|
||||
pkt->size = utf8_sub.size();
|
||||
pkt->pts = Timecode::time_to_timestamp(sub_block->in(), subtitle_codec_ctx_->time_base, Timecode::kFloor);
|
||||
pkt->duration = av_rescale_q(qRound64(sub_block->length().toDouble() * 1000), {1, 1000}, subtitle_codec_ctx_->time_base);
|
||||
pkt->dts = pkt->pts;
|
||||
av_packet_rescale_ts(pkt, subtitle_codec_ctx_->time_base, subtitle_stream_->time_base);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user