Mercurial > mplayer.hg
comparison libmpdemux/muxer_mpeg.c @ 18192:0b77e66a7d32
introduced new functions to handle pack writing and interleaving strategy (will soon replace current ones)
author | nicodvb |
---|---|
date | Sat, 22 Apr 2006 15:41:16 +0000 |
parents | 7d83cd632b6b |
children | f7f6984638f8 |
comparison
equal
deleted
inserted
replaced
18191:0b8ca8721411 | 18192:0b77e66a7d32 |
---|---|
986 spriv->framebuf[i] = tmp; | 986 spriv->framebuf[i] = tmp; |
987 } | 987 } |
988 spriv->framebuf_used -= n; | 988 spriv->framebuf_used -= n; |
989 } | 989 } |
990 | 990 |
991 static int calc_packet_len(muxer_stream_t *s, int psize, int finalize) | |
992 { | |
993 muxer_headers_t *spriv = s->priv; | |
994 int n, len, frpos, m; | |
995 | |
996 n = len = 0; | |
997 frpos = spriv->framebuf[0].pos; | |
998 while(len < psize && n < spriv->framebuf_used) | |
999 { | |
1000 if(!frpos && len>0 && s->type == MUXER_TYPE_VIDEO && spriv->framebuf[n].type==I_FRAME) | |
1001 return len; | |
1002 m = min(spriv->framebuf[n].size - frpos, psize - len); | |
1003 len += m; | |
1004 frpos += m; | |
1005 if(frpos == spriv->framebuf[n].size) | |
1006 { | |
1007 frpos = 0; | |
1008 n++; | |
1009 } | |
1010 } | |
1011 | |
1012 if(len < psize && !finalize) | |
1013 return 0; | |
1014 return len; | |
1015 } | |
1016 | |
1017 static int find_packet_timestamps(muxer_priv_t *priv, muxer_stream_t *s, uint64_t *dts, uint64_t *pts) | |
1018 { | |
1019 muxer_headers_t *spriv = s->priv; | |
1020 int i, m, pes_hlen, ret, threshold; | |
1021 uint64_t spts, sdts, dpts; | |
1022 | |
1023 if(!spriv->framebuf_used) | |
1024 return 0; | |
1025 | |
1026 spts = spriv->pts; | |
1027 sdts = spriv->dts; | |
1028 spriv->dts = spriv->pts = 0; | |
1029 ret = 0; | |
1030 if(spriv->framebuf[0].pos == 0) // start of frame | |
1031 i = 0; | |
1032 else | |
1033 { | |
1034 pes_hlen = calc_pes_hlen(priv->mux, spriv, priv); | |
1035 | |
1036 if(pes_hlen < spriv->min_pes_hlen) | |
1037 pes_hlen = spriv->min_pes_hlen; | |
1038 | |
1039 m = spriv->framebuf[0].size - spriv->framebuf[0].pos; | |
1040 | |
1041 if(spriv->pack_offset + pes_hlen + m >= priv->packet_size) | |
1042 i = -1; //this pack won't have a pts: no space available | |
1043 else | |
1044 { | |
1045 if(spriv->framebuf_used < 2) | |
1046 goto fail; | |
1047 | |
1048 if(spriv->framebuf[1].pts == spriv->framebuf[1].dts) | |
1049 threshold = 5; | |
1050 else | |
1051 threshold = 10; | |
1052 | |
1053 //headers+frame 0 < space available including timestamps | |
1054 if(spriv->pack_offset + pes_hlen + m < priv->packet_size - threshold) | |
1055 i = 1; | |
1056 else | |
1057 i = -1; | |
1058 } | |
1059 } | |
1060 | |
1061 if(i > -1) | |
1062 { | |
1063 dpts = max(spriv->last_saved_pts, spriv->framebuf[i].pts) - | |
1064 min(spriv->last_saved_pts, spriv->framebuf[i].pts) + | |
1065 spriv->framebuf[0].idur; | |
1066 | |
1067 if(s->type != MUXER_TYPE_VIDEO) | |
1068 ret = 1; | |
1069 else if((spriv->framebuf[i].type == I_FRAME || priv->ts_allframes || dpts >= 45000*300)) //0.5 seconds | |
1070 ret = 1; | |
1071 | |
1072 if(ret) | |
1073 { | |
1074 *pts = spriv->framebuf[i].pts; | |
1075 *dts = spriv->framebuf[i].dts; | |
1076 if(*dts == *pts) | |
1077 *dts = 0; | |
1078 //spriv->last_saved_pts = spriv->pts; | |
1079 } | |
1080 } | |
1081 | |
1082 fail: | |
1083 spriv->pts = spts; | |
1084 spriv->dts = sdts; | |
1085 return ret; | |
1086 } | |
1087 | |
1088 | |
1089 static int fill_packet(muxer_t *muxer, muxer_stream_t *s, int finalize) | |
1090 { | |
1091 //try to fill a packet as much as possible | |
1092 //spriv->pack_offset is the start position inited to 0 | |
1093 //data is taken from spriv->framebuf | |
1094 //if audio and a52 insert the headers | |
1095 muxer_priv_t *priv = (muxer_priv_t *) muxer->priv; | |
1096 muxer_headers_t *spriv = (muxer_headers_t *) s->priv; | |
1097 int pes_hlen = 0, len, stflen, stuffing_len, i, m, n, testlen, frpos, dvd_pack = 0, len2, target, hlen; | |
1098 uint64_t spts, sdts, pts=0, dts=0; | |
1099 mpeg_frame_t *frm; | |
1100 | |
1101 spts = spriv->pts; | |
1102 sdts = spriv->dts; | |
1103 | |
1104 if(! spriv->framebuf_used) | |
1105 { | |
1106 spriv->pack_offset = 0; | |
1107 return 0; | |
1108 } | |
1109 | |
1110 if(!spriv->pack_offset) | |
1111 { | |
1112 spriv->pack_offset = write_mpeg_pack_header(muxer, spriv->pack); | |
1113 if(priv->update_system_header && (priv->is_genmpeg1 || priv->is_genmpeg2)) | |
1114 { | |
1115 spriv->pack_offset += write_mpeg_system_header(muxer, &spriv->pack[spriv->pack_offset]); | |
1116 priv->update_system_header = 0; | |
1117 } | |
1118 spriv->pes_set = 0; | |
1119 spriv->pes_offset = spriv->pack_offset; | |
1120 spriv->payload_offset = 0; | |
1121 spriv->frames = 0; | |
1122 spriv->last_frame_rest = 0; | |
1123 } | |
1124 | |
1125 if(!spriv->pes_set) | |
1126 { | |
1127 //search the pts. yes if either it's video && (I-frame or priv->ts_allframes) && framebuf[i].pos == 0 | |
1128 //or it's audio && framebuf[i].pos == 0 | |
1129 //NB pts and dts can only be relative to the first frame beginning in this pack | |
1130 if((priv->is_xsvcd || priv->is_xvcd) && spriv->size == 0) | |
1131 spriv->buffer_size = 4*1024; | |
1132 | |
1133 if(priv->is_dvd && s->type == MUXER_TYPE_VIDEO | |
1134 && spriv->framebuf[0].type==I_FRAME && spriv->framebuf[0].pos==0) | |
1135 dvd_pack = 1; | |
1136 | |
1137 spriv->dts = spriv->pts = 0; | |
1138 if(find_packet_timestamps(priv, s, &dts, &pts)) | |
1139 { | |
1140 spriv->pts = pts; | |
1141 spriv->dts = dts; | |
1142 spriv->last_saved_pts = pts; | |
1143 } | |
1144 | |
1145 pes_hlen = calc_pes_hlen(priv->mux, spriv, priv); | |
1146 stflen = (spriv->min_pes_hlen > pes_hlen ? spriv->min_pes_hlen - pes_hlen : 0); | |
1147 | |
1148 target = len = priv->packet_size - spriv->pack_offset - pes_hlen - stflen; //max space available | |
1149 if(s->type == MUXER_TYPE_AUDIO && s->wf->wFormatTag == AUDIO_A52) | |
1150 hlen = 4; | |
1151 else | |
1152 hlen = 0; | |
1153 | |
1154 len -= hlen; | |
1155 target -= hlen; | |
1156 | |
1157 len2 = calc_packet_len(s, target, finalize); | |
1158 if(!len2) | |
1159 { | |
1160 spriv->pack_offset = 0; | |
1161 return 0; | |
1162 } | |
1163 if(len2 < target) | |
1164 { | |
1165 if(s->type == MUXER_TYPE_AUDIO && !finalize) | |
1166 { | |
1167 spriv->pack_offset = 0; | |
1168 spriv->pts = spts; | |
1169 spriv->dts = sdts; | |
1170 return 0; | |
1171 } | |
1172 } | |
1173 len = len2; | |
1174 stuffing_len = 0; | |
1175 if(len < target) | |
1176 { | |
1177 if(s->type == MUXER_TYPE_VIDEO) //FIXME: check i_frame | |
1178 { | |
1179 if(spriv->pts) | |
1180 target += 5; | |
1181 if(spriv->dts) | |
1182 target += 5; | |
1183 spriv->pts = spriv->dts = 0; | |
1184 } | |
1185 | |
1186 stuffing_len = target - len; | |
1187 if(stuffing_len > 0 && stuffing_len < 7) | |
1188 { | |
1189 if(stflen + stuffing_len > 16) | |
1190 { | |
1191 int x = 7 - stuffing_len; | |
1192 stflen -= x; | |
1193 stuffing_len += x; | |
1194 | |
1195 /*int x = stflen + stuffing_len; | |
1196 stflen = 16; | |
1197 stuffing_len = x - stflen; | |
1198 */ | |
1199 } | |
1200 else | |
1201 { | |
1202 stflen += stuffing_len; | |
1203 stuffing_len = 0; | |
1204 } | |
1205 } | |
1206 } | |
1207 | |
1208 len += hlen; | |
1209 spriv->pack_offset += write_mpeg_pes_header(spriv, (uint8_t *) &s->ckid, &(spriv->pack[spriv->pack_offset]), | |
1210 len, stflen, priv->mux); | |
1211 | |
1212 if(s->type == MUXER_TYPE_AUDIO && s->wf->wFormatTag == AUDIO_A52) | |
1213 { | |
1214 spriv->payload_offset = spriv->pack_offset; | |
1215 spriv->pack_offset += 4; //for the 4 bytes of header | |
1216 if(!spriv->framebuf[0].pos) | |
1217 spriv->last_frame_rest = 0; | |
1218 else | |
1219 spriv->last_frame_rest = spriv->framebuf[0].size - spriv->framebuf[0].pos; | |
1220 } | |
1221 | |
1222 spriv->pes_set = 1; | |
1223 } | |
1224 | |
1225 | |
1226 if(spriv->dts || spriv->pts) | |
1227 { | |
1228 if((spriv->dts && priv->scr >= spriv->dts) || priv->scr >= spriv->pts) | |
1229 mp_msg(MSGT_MUXER, MSGL_ERR, "\r\nERROR: scr %.3lf, dts %.3lf, pts %.3lf\r\n", (double) priv->scr/27000000.0, (double) spriv->dts/27000000.0, (double) spriv->pts/27000000.0); | |
1230 else if(priv->scr + 63000*300 < spriv->dts) | |
1231 mp_msg(MSGT_MUXER, MSGL_INFO, "\r\nWARNING>: scr %.3lf, dts %.3lf, pts %.3lf, diff %.3lf, piff %.3lf\r\n", (double) priv->scr/27000000.0, (double) spriv->dts/27000000.0, (double) spriv->pts/27000000.0, (double)(spriv->dts - priv->scr)/27000000.0, (double)(spriv->pts - priv->scr)/27000000.0); | |
1232 } | |
1233 | |
1234 n = 0; | |
1235 len = 0; | |
1236 testlen = 0; | |
1237 | |
1238 frm = spriv->framebuf; | |
1239 while(spriv->pack_offset < priv->packet_size && n < spriv->framebuf_used) | |
1240 { | |
1241 if(!frm->pos) | |
1242 { | |
1243 //since iframes must always be aligned at block boundaries exit when we find the | |
1244 //beginning of one in the middle of the flush | |
1245 if(len > 0 && s->type == MUXER_TYPE_VIDEO && frm->type == I_FRAME) | |
1246 { | |
1247 testlen = len; | |
1248 break; | |
1249 } | |
1250 spriv->frames++; | |
1251 update_demux_bufsize(spriv, frm->dts, frm->size, s->type); | |
1252 } | |
1253 | |
1254 m = min(frm->size - frm->pos, priv->packet_size - spriv->pack_offset); | |
1255 memcpy(&(spriv->pack[spriv->pack_offset]), &(frm->buffer[frm->pos]), m); | |
1256 | |
1257 len += m; | |
1258 spriv->pack_offset += m; | |
1259 frm->pos += m; | |
1260 | |
1261 if(frm->pos == frm->size) //end of frame | |
1262 { | |
1263 frm->pos = frm->size = 0; | |
1264 frm->pts = frm->dts = 0; | |
1265 n++; | |
1266 frm++; | |
1267 } | |
1268 } | |
1269 | |
1270 if((priv->is_xsvcd || priv->is_xvcd) && spriv->size == 0) | |
1271 spriv->buffer_size = 0; | |
1272 | |
1273 spriv->size += len; | |
1274 | |
1275 if(dvd_pack && (spriv->pack_offset == priv->packet_size)) | |
1276 write_mpeg_pack(muxer, s, muxer->file, NULL, 0, 0); //insert fake Nav Packet | |
1277 | |
1278 if(n > 0) | |
1279 remove_frames(spriv, n); | |
1280 | |
1281 spriv->track_bufsize += len; | |
1282 if(spriv->track_bufsize > spriv->max_buffer_size) | |
1283 mp_msg(MSGT_MUXER, MSGL_ERR, "\r\nBUFFER OVERFLOW: %d > %d\r\n", spriv->track_bufsize, spriv->max_buffer_size); | |
1284 | |
1285 if(s->type == MUXER_TYPE_AUDIO && s->wf->wFormatTag == AUDIO_A52) | |
1286 fix_a52_headers(s); | |
1287 | |
1288 if(spriv->pack_offset < priv->packet_size) //here finalize is set | |
1289 { | |
1290 int diff = priv->packet_size - spriv->pack_offset; | |
1291 write_pes_padding(&(spriv->pack[spriv->pack_offset]), diff); | |
1292 spriv->pack_offset += diff; | |
1293 } | |
1294 | |
1295 fwrite(spriv->pack, spriv->pack_offset, 1, muxer->file); | |
1296 | |
1297 priv->headers_size += spriv->pack_offset - len; | |
1298 priv->data_size += len; | |
1299 muxer->movi_end += spriv->pack_offset; | |
1300 | |
1301 spriv->pack_offset = 0; | |
1302 spriv->pes_set = 0; | |
1303 spriv->frames = 0; | |
1304 | |
1305 spriv->pts = spts; | |
1306 spriv->dts = sdts; | |
1307 | |
1308 return len; | |
1309 } | |
1310 | |
1311 static inline int find_best_stream(muxer_t *muxer) | |
1312 { | |
1313 int i, ndts; | |
1314 uint64_t dts = -1; | |
1315 muxer_priv_t *priv = muxer->priv; | |
1316 muxer_headers_t *spriv; | |
1317 | |
1318 ndts = -1; | |
1319 | |
1320 //MUST ALWAYS apply: [pd]ts < SCR + 0.7 seconds | |
1321 //FIXME: find pack_dts and pack_len instead, for the time being the code below is still reasonable | |
1322 for(i = 0; i < muxer->avih.dwStreams; i++) | |
1323 { | |
1324 spriv = muxer->streams[i]->priv; | |
1325 | |
1326 if(! spriv->framebuf_used || spriv->track_bufsize + priv->packet_size - 20 > spriv->max_buffer_size) | |
1327 continue; | |
1328 //59000 ~= 0.7 seconds - max(frame_duration) (<42 ms at 23.976 fps) | |
1329 if(spriv->framebuf[0].pts > priv->scr + 59000*300) | |
1330 continue; | |
1331 | |
1332 if(spriv->framebuf[0].dts <= dts) | |
1333 { | |
1334 dts = spriv->framebuf[0].dts; | |
1335 ndts = i; | |
1336 } | |
1337 } | |
1338 | |
1339 return ndts; | |
1340 } | |
1341 | |
991 static void patch_seq(muxer_priv_t *priv, unsigned char *buf) | 1342 static void patch_seq(muxer_priv_t *priv, unsigned char *buf) |
992 { | 1343 { |
993 if(priv->vwidth > 0) | 1344 if(priv->vwidth > 0) |
994 { | 1345 { |
995 buf[4] = (priv->vwidth >> 4) & 0xff; | 1346 buf[4] = (priv->vwidth >> 4) & 0xff; |