private void mvZero(Context context, PictureHeader ph, MPEGPred pred, int mbX, int mbY, int[][] mbPix) { if (ph.picture_coding_type == PictureHeader.PredictiveCoded) { pred.predict16x16NoMV(refFrames[0], mbX << 4, mbY << 4, ph.pictureCodingExtension == null ? PictureCodingExtension.Frame : ph.pictureCodingExtension.picture_structure, 0, mbPix); } else { int[][] pp = mbPix; if (context.lastPredB.macroblock_motion_backward == 1) { pred.predict16x16NoMV(refFrames[0], mbX << 4, mbY << 4, ph.pictureCodingExtension == null ? PictureCodingExtension.Frame : ph.pictureCodingExtension.picture_structure, 1, pp); pp = new int[][] { new int[mbPix[0].Length], new int[mbPix[1].Length], new int[mbPix[2].Length] }; } if (context.lastPredB.macroblock_motion_forward == 1) { pred.predict16x16NoMV(refFrames[1], mbX << 4, mbY << 4, ph.pictureCodingExtension == null ? PictureCodingExtension.Frame : ph.pictureCodingExtension.picture_structure, 0, pp); if (mbPix != pp) { avgPred(mbPix, pp); } } } }
public static PictureHeader read(MemoryStream bb) { BitReader inb = new BitReader(bb); PictureHeader ph = new PictureHeader(); ph.temporal_reference = inb.readNBit(10); ph.picture_coding_type = inb.readNBit(3); ph.vbv_delay = inb.readNBit(16); if (ph.picture_coding_type == 2 || ph.picture_coding_type == 3) { ph.full_pel_forward_vector = inb.read1Bit(); ph.forward_f_code = inb.readNBit(3); } if (ph.picture_coding_type == 3) { ph.full_pel_backward_vector = inb.read1Bit(); ph.backward_f_code = inb.readNBit(3); } while (inb.read1Bit() == 1) { inb.readNBit(8); } return(ph); }
public Picture decodeFrame(MemoryStream ByteBuffer, int[][] buf) { PictureHeader ph = readHeader(ByteBuffer); if (refFrames[0] == null && ph.picture_coding_type > 1 || refFrames[1] == null && ph.picture_coding_type > 2) { throw new Exception("Not enough references to decode " + (ph.picture_coding_type == 1 ? "P" : "B") + " frame"); } Context context = initContext(sh, ph); Picture pic = new Picture(context.codedWidth, context.codedHeight, buf, context.color, new Rect(0, 0, context.picWidth, context.picHeight)); if (ph.pictureCodingExtension != null && ph.pictureCodingExtension.picture_structure != PictureCodingExtension.Frame) { decodePicture(context, ph, ByteBuffer, buf, ph.pictureCodingExtension.picture_structure - 1, 1); ph = readHeader(ByteBuffer); context = initContext(sh, ph); decodePicture(context, ph, ByteBuffer, buf, ph.pictureCodingExtension.picture_structure - 1, 1); } else { decodePicture(context, ph, ByteBuffer, buf, 0, 0); } if (ph.picture_coding_type == PictureHeader.IntraCoded || ph.picture_coding_type == PictureHeader.PredictiveCoded) { Picture unused = refFrames[1]; refFrames[1] = refFrames[0]; refFrames[0] = copyAndCreateIfNeeded(pic, unused); } return(pic); }
private void resetDCPredictors(Context context, PictureHeader ph) { int rval = 1 << 7; if (ph.pictureCodingExtension != null) { rval = 1 << (7 + ph.pictureCodingExtension.intra_dc_precision); } context.intra_dc_predictor[0] = context.intra_dc_predictor[1] = context.intra_dc_predictor[2] = rval; }
public Picture decodePicture(Context context, PictureHeader ph, MemoryStream buffer, int[][] buf, int vertOff, int vertStep) { int planeSize = context.codedWidth * context.codedHeight; if (buf.Length < 3 || buf[0].Length < planeSize || buf[1].Length < planeSize || buf[2].Length < planeSize) { throw new Exception("ByteBuffer too small to hold output picture [" + context.codedWidth + "x" + context.codedHeight + "]"); } try { MemoryStream segment; while ((segment = MPEGUtil.nextSegment(buffer)) != null) { if (segment.get(3) >= MPEGConst.SLICE_START_CODE_FIRST && segment.get(3) <= MPEGConst.SLICE_START_CODE_LAST) { segment.position(4); try { decodeSlice(ph, segment.get(3) & 0xff, context, buf, new BitReader(segment), vertOff, vertStep); } catch (Exception e) { //e.printStackTrace(); } } else if (segment.get(3) >= 0xB3 && segment.get(3) != 0xB6 && segment.get(3) != 0xB7) { throw new Exception("Unexpected start code " + segment.get(3)); } else if (segment.get(3) == 0x0) { //buffer.reset(); break; } } Picture pic = new Picture(context.codedWidth, context.codedHeight, buf, context.color); if ((ph.picture_coding_type == PictureHeader.IntraCoded || ph.picture_coding_type == PictureHeader.PredictiveCoded) && ph.pictureCodingExtension != null && ph.pictureCodingExtension.picture_structure != PictureCodingExtension.Frame) { refFields[ph.pictureCodingExtension.picture_structure - 1] = copyAndCreateIfNeeded(pic, refFields[ph.pictureCodingExtension.picture_structure - 1]); } return(pic); } catch (IOException e) { throw e; } }
private PictureHeader readHeader(MemoryStream buffer) { PictureHeader ph = null; MemoryStream segment; MemoryStream fork = buffer.duplicate(); while ((segment = MPEGUtil.nextSegment(fork)) != null) { int code = segment.getInt() & 0xff; if (code == MPEGConst.SEQUENCE_HEADER_CODE) { SequenceHeader newSh = SequenceHeader.read(segment); if (sh != null) { newSh.copyExtensions(sh); } sh = newSh; } else if (code == MPEGConst.GROUP_START_CODE) { gh = GOPHeader.read(segment); } else if (code == MPEGConst.PICTURE_START_CODE) { ph = PictureHeader.read(segment); } else if (code == MPEGConst.EXTENSION_START_CODE) { int extType = segment.get(4) >> 4; if (extType == SequenceHeader.Sequence_Extension || extType == SequenceHeader.Sequence_Scalable_Extension || extType == SequenceHeader.Sequence_Display_Extension) { SequenceHeader.readExtension(segment, sh); } else { PictureHeader.readExtension(segment, ph, sh); } } else if (code == MPEGConst.USER_DATA_START_CODE) { // do nothing } else { break; } buffer.position(fork.position()); } return(ph); }
protected Context initContext(SequenceHeader sh, PictureHeader ph) { Context context = new Context(); context.codedWidth = (sh.horizontal_size + 15) & ~0xf; context.codedHeight = getCodedHeight(sh, ph); context.mbWidth = (sh.horizontal_size + 15) >> 4; context.mbHeight = (sh.vertical_size + 15) >> 4; context.picWidth = sh.horizontal_size; context.picHeight = sh.vertical_size; int chromaFormat = SequenceExtension.Chroma420; if (sh.sequenceExtension != null) { chromaFormat = sh.sequenceExtension.chroma_format; } context.color = getColor(chromaFormat); context.scan = MPEGConst.scan[ph.pictureCodingExtension == null ? 0 : ph.pictureCodingExtension.alternate_scan]; int[] inter = sh.non_intra_quantiser_matrix == null?zigzag(MPEGConst.defaultQMatInter, context.scan) : sh.non_intra_quantiser_matrix; int[] intra = sh.intra_quantiser_matrix == null?zigzag(MPEGConst.defaultQMatIntra, context.scan) : sh.intra_quantiser_matrix; context.qMats = new int[][] { inter, inter, intra, intra }; if (ph.quantMatrixExtension != null) { if (ph.quantMatrixExtension.non_intra_quantiser_matrix != null) { context.qMats[0] = ph.quantMatrixExtension.non_intra_quantiser_matrix; } if (ph.quantMatrixExtension.chroma_non_intra_quantiser_matrix != null) { context.qMats[1] = ph.quantMatrixExtension.chroma_non_intra_quantiser_matrix; } if (ph.quantMatrixExtension.intra_quantiser_matrix != null) { context.qMats[2] = ph.quantMatrixExtension.intra_quantiser_matrix; } if (ph.quantMatrixExtension.chroma_intra_quantiser_matrix != null) { context.qMats[3] = ph.quantMatrixExtension.chroma_intra_quantiser_matrix; } } return(context); }
public void decodeSlice(PictureHeader ph, int verticalPos, Context context, int[][] buf, BitReader ing, int vertOff, int vertStep) { int stride = context.codedWidth; resetDCPredictors(context, ph); int mbRow = verticalPos - 1; if (sh.vertical_size > 2800) { mbRow += (ing.readNBit(3) << 7); } if (sh.sequenceScalableExtension != null && sh.sequenceScalableExtension.scalable_mode == SequenceScalableExtension.DATA_PARTITIONING) { int priorityBreakpoint = ing.readNBit(7); } int qScaleCode = ing.readNBit(5); if (ing.read1Bit() == 1) { int intraSlice = ing.read1Bit(); ing.skip(7); while (ing.read1Bit() == 1) { ing.readNBit(8); } } MPEGPred pred = new MPEGPred(ph.pictureCodingExtension != null ? ph.pictureCodingExtension.f_code : new int[][] { new int[] { ph.forward_f_code, ph.forward_f_code }, new int[] { ph.backward_f_code, ph.backward_f_code } }, sh.sequenceExtension != null ? sh.sequenceExtension.chroma_format : SequenceExtension.Chroma420, ph.pictureCodingExtension != null && ph.pictureCodingExtension.top_field_first == 0 ? false : true); int[] ctx = new int[] { qScaleCode }; for (int prevAddr = mbRow * context.mbWidth - 1; ing.checkNBit(23) != 0;) { // TODO: decode skipped!!! prevAddr = decodeMacroblock(ph, context, prevAddr, ctx, buf, stride, ing, vertOff, vertStep, pred); context.mbNo++; } }
public static void readExtension(MemoryStream bb, PictureHeader ph, SequenceHeader sh) { ph.m_hasExtensions = true; BitReader inb = new BitReader(bb); int extType = inb.readNBit(4); switch (extType) { case Quant_Matrix_Extension: ph.quantMatrixExtension = QuantMatrixExtension.read(inb); break; case Copyright_Extension: ph.copyrightExtension = CopyrightExtension.read(inb); break; case Picture_Display_Extension: ph.pictureDisplayExtension = PictureDisplayExtension.read(inb, sh.sequenceExtension, ph.pictureCodingExtension); break; case Picture_Coding_Extension: ph.pictureCodingExtension = PictureCodingExtension.read(inb); break; case Picture_Spatial_Scalable_Extension: ph.pictureSpatialScalableExtension = PictureSpatialScalableExtension.read(inb); break; case Picture_Temporal_Scalable_Extension: ph.pictureTemporalScalableExtension = PictureTemporalScalableExtension.read(inb); break; default: throw new Exception("Unsupported extension: " + extType); } }
public int decodeMacroblock(PictureHeader ph, Context context, int prevAddr, int[] qScaleCode, int[][] buf, int stride, BitReader bits, int vertOff, int vertStep, MPEGPred pred) { int mbAddr = prevAddr; while (bits.checkNBit(11) == 0x8) { bits.skip(11); mbAddr += 33; } mbAddr += MPEGConst.vlcAddressIncrement.readVLC(bits) + 1; int chromaFormat = SequenceExtension.Chroma420; if (sh.sequenceExtension != null) { chromaFormat = sh.sequenceExtension.chroma_format; } for (int i = prevAddr + 1; i < mbAddr; i++) { int[][] predFwda = new int[][] { new int[256], new int[1 << (chromaFormat + 5)], new int[1 << (chromaFormat + 5)] }; int mbXa = i % context.mbWidth; int mbYa = i / context.mbWidth; if (ph.picture_coding_type == PictureHeader.PredictiveCoded) { pred.reset(); } mvZero(context, ph, pred, mbXa, mbYa, predFwda); put(predFwda, buf, stride, chromaFormat, mbXa, mbYa, context.codedWidth, context.codedHeight >> vertStep, vertOff, vertStep); } VLC vlcMBTypea = MPEGConst.vlcMBType(ph.picture_coding_type, sh.sequenceScalableExtension); nVideo.Codecs.MPEG12.MPEGConst.MBType[] mbTypeVal = MPEGConst.mbTypeVal(ph.picture_coding_type, sh.sequenceScalableExtension); nVideo.Codecs.MPEG12.MPEGConst.MBType mbType = mbTypeVal[vlcMBTypea.readVLC(bits)]; if (mbType.macroblock_intra != 1 || (mbAddr - prevAddr) > 1) { resetDCPredictors(context, ph); } int spatial_temporal_weight_code = 0; if (mbType.spatial_temporal_weight_code_flag == 1 && ph.pictureSpatialScalableExtension != null && ph.pictureSpatialScalableExtension.spatial_temporal_weight_code_table_index != 0) { spatial_temporal_weight_code = bits.readNBit(2); } int motion_type = -1; if (mbType.macroblock_motion_forward != 0 || mbType.macroblock_motion_backward != 0) { if (ph.pictureCodingExtension == null || ph.pictureCodingExtension.picture_structure == PictureCodingExtension.Frame && ph.pictureCodingExtension.frame_pred_frame_dct == 1) { motion_type = 2; } else { motion_type = bits.readNBit(2); } } int dctType = 0; if (ph.pictureCodingExtension != null && ph.pictureCodingExtension.picture_structure == PictureCodingExtension.Frame && ph.pictureCodingExtension.frame_pred_frame_dct == 0 && (mbType.macroblock_intra != 0 || mbType.macroblock_pattern != 0)) { dctType = bits.read1Bit(); } // buf[3][mbAddr] = dctType; if (mbType.macroblock_quant != 0) { qScaleCode[0] = bits.readNBit(5); } bool concealmentMv = ph.pictureCodingExtension != null && ph.pictureCodingExtension.concealment_motion_vectors != 0; int[][] predFwd = null; int mbX = mbAddr % context.mbWidth; int mbY = mbAddr / context.mbWidth; if (mbType.macroblock_intra == 1) { if (concealmentMv) { // TODO read consealment vectors } else { pred.reset(); } } else if (mbType.macroblock_motion_forward != 0) { int refIdx = ph.picture_coding_type == PictureHeader.PredictiveCoded ? 0 : 1; predFwd = new int[][] { new int[256], new int[1 << (chromaFormat + 5)], new int[1 << (chromaFormat + 5)] }; if (ph.pictureCodingExtension == null || ph.pictureCodingExtension.picture_structure == PictureCodingExtension.Frame) { pred.predictInFrame(refFrames[refIdx], mbX << 4, mbY << 4, predFwd, bits, motion_type, 0, spatial_temporal_weight_code); } else { if (ph.picture_coding_type == PictureHeader.PredictiveCoded) { pred.predictInField(refFields, mbX << 4, mbY << 4, predFwd, bits, motion_type, 0, ph.pictureCodingExtension.picture_structure - 1); } else { pred.predictInField(new Picture[] { refFrames[refIdx], refFrames[refIdx] }, mbX << 4, mbY << 4, predFwd, bits, motion_type, 0, ph.pictureCodingExtension.picture_structure - 1); } } } else if (ph.picture_coding_type == PictureHeader.PredictiveCoded) { predFwd = new int[][] { new int[256], new int[1 << (chromaFormat + 5)], new int[1 << (chromaFormat + 5)] }; pred.reset(); mvZero(context, ph, pred, mbX, mbY, predFwd); } int[][] predBack = null; if (mbType.macroblock_motion_backward != 0) { predBack = new int[][] { new int[256], new int[1 << (chromaFormat + 5)], new int[1 << (chromaFormat + 5)] }; if (ph.pictureCodingExtension == null || ph.pictureCodingExtension.picture_structure == PictureCodingExtension.Frame) { pred.predictInFrame(refFrames[0], mbX << 4, mbY << 4, predBack, bits, motion_type, 1, spatial_temporal_weight_code); } else { pred.predictInField(new Picture[] { refFrames[0], refFrames[0] }, mbX << 4, mbY << 4, predBack, bits, motion_type, 1, ph.pictureCodingExtension.picture_structure - 1); } } context.lastPredB = mbType; int[][] pp = mbType.macroblock_intra == 1 ? new int[][] { new int[256], new int[1 << (chromaFormat + 5)], new int[1 << (chromaFormat + 5)] } : buildPred(predFwd, predBack); //if (mbType.macroblock_intra != 0 && concealmentMv) //Assert.assertEquals(1, bits.read1Bit()); // Marker int cbp = mbType.macroblock_intra == 1 ? 0xfff : 0; if (mbType.macroblock_pattern != 0) { cbp = readCbPattern(bits); } VLC vlcCoeff = MPEGConst.vlcCoeff0; if (ph.pictureCodingExtension != null && mbType.macroblock_intra == 1 && ph.pictureCodingExtension.intra_vlc_format == 1) { vlcCoeff = MPEGConst.vlcCoeff1; } int[] qScaleTab = ph.pictureCodingExtension != null && ph.pictureCodingExtension.q_scale_type == 1 ? MPEGConst.qScaleTab2 : MPEGConst.qScaleTab1; int qScale = qScaleTab[qScaleCode[0]]; int intra_dc_mult = 8; if (ph.pictureCodingExtension != null) { intra_dc_mult = 8 >> ph.pictureCodingExtension.intra_dc_precision; } int blkCount = 6 + (chromaFormat == SequenceExtension.Chroma420 ? 0 : (chromaFormat == SequenceExtension.Chroma422 ? 2 : 6)); int[] block = new int[64]; // System.out.print(mbAddr + ": "); for (int i = 0, cbpMask = 1 << (blkCount - 1); i < blkCount; i++, cbpMask >>= 1) { if ((cbp & cbpMask) == 0) { continue; } int[] qmat = context.qMats[(i >= 4 ? 1 : 0) + (mbType.macroblock_intra << 1)]; if (mbType.macroblock_intra == 1) { blockIntra(bits, vlcCoeff, block, context.intra_dc_predictor, i, context.scan, sh.hasExtensions() || ph.hasExtensions() ? 12 : 8, intra_dc_mult, qScale, qmat); } else { blockInter(bits, vlcCoeff, block, context.scan, sh.hasExtensions() || ph.hasExtensions() ? 12 : 8, qScale, qmat); } mapBlock(block, pp[MPEGConst.BLOCK_TO_CC[i]], i, dctType, chromaFormat); } put(pp, buf, stride, chromaFormat, mbX, mbY, context.codedWidth, context.codedHeight >> vertStep, vertOff, vertStep); return(mbAddr); }
public static int getCodedHeight(SequenceHeader sh, PictureHeader ph) { int field = ph.pictureCodingExtension != null && ph.pictureCodingExtension.picture_structure != PictureCodingExtension.Frame ? 1 : 0; return((((sh.vertical_size >> field) + 15) & ~0xf) << field); }