From a5576e56f060f224b63f8bfe1bc12ff95ff210b7 Mon Sep 17 00:00:00 2001
From: Gavin Hurlbut <ghurlbut@mythtv.org>
Date: Sun, 23 Sep 2012 19:09:07 -0700
Subject: [PATCH] Fix video encode in MPEG2 "lossless" transcoding
Fixes #11118
It seems that the new video encode API call pipelines the encoding, returning
after each input frame, but not returning a packet the first time around in all
cases. This change makes it encode the packet, and then keep calling the API
until a packet has actually been encoded (flushing the output).
---
mythtv/programs/mythtranscode/mpeg2fix.cpp | 39 +++++++++++++++------------
mythtv/programs/mythtranscode/mpeg2fix.h | 2 +-
2 files changed, 23 insertions(+), 18 deletions(-)
diff --git a/mythtv/programs/mythtranscode/mpeg2fix.cpp b/mythtv/programs/mythtranscode/mpeg2fix.cpp
index 0550e0b..23184f1 100644
a
|
b
|
extern "C" { |
1063 | 1063 | #include "helper.h" |
1064 | 1064 | } |
1065 | 1065 | |
1066 | | int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) |
| 1066 | bool MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) |
1067 | 1067 | { |
1068 | 1068 | const mpeg2_info_t *info; |
1069 | 1069 | int outbuf_size; |
… |
… |
int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) |
1074 | 1074 | |
1075 | 1075 | info = mpeg2_info(img_decoder); |
1076 | 1076 | if (!info->display_fbuf) |
1077 | | return 1; |
| 1077 | return true; |
1078 | 1078 | |
1079 | 1079 | outbuf_size = info->sequence->width * info->sequence->height * 2; |
1080 | 1080 | |
… |
… |
int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) |
1116 | 1116 | { |
1117 | 1117 | free(picture); |
1118 | 1118 | LOG(VB_GENERAL, LOG_ERR, "Couldn't find MPEG2 encoder"); |
1119 | | return 1; |
| 1119 | return true; |
1120 | 1120 | } |
1121 | 1121 | |
1122 | 1122 | c = avcodec_alloc_context3(NULL); |
1123 | 1123 | |
1124 | | //We disable all optimizations for the time being. There shouldn't be too |
1125 | | //much encoding going on, and the optimizations have been shown to cause |
1126 | | //corruption in some cases |
1127 | | c->dsp_mask = 0xffff; |
1128 | | |
1129 | 1124 | //NOTE: The following may seem wrong, but avcodec requires |
1130 | 1125 | //sequence->progressive == frame->progressive |
1131 | 1126 | //We fix the discrepancy by discarding avcodec's sequence header, and |
… |
… |
int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) |
1164 | 1159 | { |
1165 | 1160 | free(picture); |
1166 | 1161 | LOG(VB_GENERAL, LOG_ERR, "could not open codec"); |
1167 | | return 1; |
| 1162 | return true; |
1168 | 1163 | } |
1169 | 1164 | |
1170 | 1165 | int got_packet = 0; |
| 1166 | int ret; |
| 1167 | bool initial = true; |
1171 | 1168 | |
1172 | | int ret = avcodec_encode_video2(c, pkt, picture, &got_packet); |
1173 | | |
1174 | | if (ret < 0 || !got_packet) |
| 1169 | // Need to call this repeatedly as it seems to be pipelined. The first |
| 1170 | // call will return no packet, then the second one will flush it. In case |
| 1171 | // it becomes more pipelined, just loop until it creates a packet or errors |
| 1172 | // out. |
| 1173 | while (!got_packet) |
1175 | 1174 | { |
1176 | | free(picture); |
1177 | | LOG(VB_GENERAL, LOG_ERR, |
1178 | | QString("avcodec_encode_video failed (%1)").arg(pkt->size)); |
1179 | | return 1; |
| 1175 | ret = avcodec_encode_video2(c, pkt, (initial ? picture : NULL), |
| 1176 | &got_packet); |
| 1177 | |
| 1178 | if (ret < 0) |
| 1179 | { |
| 1180 | free(picture); |
| 1181 | LOG(VB_GENERAL, LOG_ERR, |
| 1182 | QString("avcodec_encode_video2 failed (%1)").arg(ret)); |
| 1183 | return true; |
| 1184 | } |
1180 | 1185 | } |
1181 | 1186 | |
1182 | 1187 | if (!fname.isEmpty()) |
… |
… |
int MPEG2fixup::BuildFrame(AVPacket *pkt, QString fname) |
1198 | 1203 | av_freep(&c); |
1199 | 1204 | av_freep(&picture); |
1200 | 1205 | |
1201 | | return 0; |
| 1206 | return false; |
1202 | 1207 | } |
1203 | 1208 | |
1204 | 1209 | #define MAX_FRAMES 20000 |
diff --git a/mythtv/programs/mythtranscode/mpeg2fix.h b/mythtv/programs/mythtranscode/mpeg2fix.h
index 96ecbbb..fe74ac0 100644
a
|
b
|
class MPEG2fixup |
171 | 171 | void WriteFrame(QString filename, AVPacket *pkt); |
172 | 172 | void WriteYUV(QString filename, const mpeg2_info_t *info); |
173 | 173 | void WriteData(QString filename, uint8_t *data, int size); |
174 | | int BuildFrame(AVPacket *pkt, QString fname); |
| 174 | bool BuildFrame(AVPacket *pkt, QString fname); |
175 | 175 | MPEG2frame *GetPoolFrame(AVPacket *pkt); |
176 | 176 | MPEG2frame *GetPoolFrame(MPEG2frame *f); |
177 | 177 | int GetFrame(AVPacket *pkt); |