/// <summary> /// /// </summary> /// <param name="avctx"></param> /// <returns></returns> override public int close(AVCodecContext avctx) { var c = (BMPContext)avctx.priv_data; if (!c.picture.data[0].IsNull) { avctx.release_buffer(avctx, c.picture); } return 0; }
/// <summary> /// /// </summary> /// <param name="avctx"></param> /// <returns></returns> public override int close(AVCodecContext avctx) { var s = (TargaContext)avctx.priv_data; if (!s.picture.data[0].IsNull) { avctx.release_buffer(avctx, s.picture); } return 0; }
/// <summary> /// /// </summary> /// <param name="avctx"></param> /// <param name="outdata"></param> /// <param name="outdata_size"></param> /// <param name="avpkt"></param> /// <returns></returns> public override int decode(AVCodecContext avctx, ref object outputData, AVPacket avpkt) { Pointer<byte> buf = avpkt.data; int buf_size = avpkt.size; BMPContext s = (BMPContext)avctx.priv_data; AVFrame p = s.picture; uint fsize, hsize; int width, height; int depth; BiCompression comp; uint ihsize; int i, n, linesize; var rgb = new uint[3]; uint alpha = 0; Pointer<byte> ptr; int dsize; Pointer<byte> buf0 = buf; if (buf_size < 14) { log.av_log(avctx, log.AV_LOG_ERROR, "buf size too small (%d)\n", buf_size); return -1; } if (bytestream.get_byte(ref buf) != 'B' || bytestream.get_byte(ref buf) != 'M') { log.av_log(avctx, log.AV_LOG_ERROR, "bad magic number\n"); return -1; } fsize = bytestream.get_le32(ref buf); if (buf_size < fsize) { log.av_log(avctx, log.AV_LOG_ERROR, "not enough data (%d < %d), trying to decode anyway\n", buf_size, fsize); fsize = (uint)buf_size; } buf += 2; /* reserved1 */ buf += 2; /* reserved2 */ hsize = bytestream.get_le32(ref buf); /* header size */ ihsize = bytestream.get_le32(ref buf); /* more header size */ if (ihsize + 14 > hsize) { log.av_log(avctx, log.AV_LOG_ERROR, "invalid header size %d\n", hsize); return -1; } /* sometimes file size is set to some headers size, set a real size in that case */ if (fsize == 14 || fsize == ihsize + 14) { fsize = (uint)(buf_size - 2); } if (fsize <= hsize) { log.av_log(avctx, log.AV_LOG_ERROR, "declared file size is less than header size (%d < %d)\n", fsize, hsize); return -1; } switch (ihsize) { case 40: // windib case 56: // windib v3 case 64: // OS/2 v2 case 108: // windib v4 case 124: // windib v5 width = (int)bytestream.get_le32(ref buf); height = (int)bytestream.get_le32(ref buf); break; case 12: // OS/2 v1 width = (int)bytestream.get_le16(ref buf); height = (int)bytestream.get_le16(ref buf); break; default: log.av_log(avctx, log.AV_LOG_ERROR, "unsupported BMP file, patch welcome\n"); return -1; } if (bytestream.get_le16(ref buf) != 1) /* planes */ { log.av_log(avctx, log.AV_LOG_ERROR, "invalid BMP header\n"); return -1; } depth = bytestream.get_le16(ref buf); if (ihsize == 40 || ihsize == 64 || ihsize == 56) { comp = (BiCompression)bytestream.get_le32(ref buf); } else { comp = BiCompression.BMP_RGB; } if (comp != BiCompression.BMP_RGB && comp != BiCompression.BMP_BITFIELDS && comp != BiCompression.BMP_RLE4 && comp != BiCompression.BMP_RLE8) { log.av_log(avctx, log.AV_LOG_ERROR, "BMP coding %d not supported\n", comp); return -1; } if (comp == BiCompression.BMP_BITFIELDS) { buf += 20; rgb[0] = bytestream.get_le32(ref buf); rgb[1] = bytestream.get_le32(ref buf); rgb[2] = bytestream.get_le32(ref buf); if (ihsize >= 108) { alpha = bytestream.get_le32(ref buf); } } avctx.width = width; avctx.height = height > 0 ? height : -height; avctx.pix_fmt = PixelFormat.PIX_FMT_NONE; switch (depth) { case 32: if (comp == BiCompression.BMP_BITFIELDS) { if (rgb[0] == 0xFF000000 && rgb[1] == 0x00FF0000 && rgb[2] == 0x0000FF00) { avctx.pix_fmt = (alpha != 0) ? PixelFormat.PIX_FMT_ABGR : PixelFormat.PIX_FMT_0BGR; } else if (rgb[0] == 0x00FF0000 && rgb[1] == 0x0000FF00 && rgb[2] == 0x000000FF) { avctx.pix_fmt = (alpha != 0) ? PixelFormat.PIX_FMT_BGRA : PixelFormat.PIX_FMT_BGR0; } else if (rgb[0] == 0x0000FF00 && rgb[1] == 0x00FF0000 && rgb[2] == 0xFF000000) { avctx.pix_fmt = (alpha != 0) ? PixelFormat.PIX_FMT_ARGB : PixelFormat.PIX_FMT_0RGB; } else if (rgb[0] == 0x000000FF && rgb[1] == 0x0000FF00 && rgb[2] == 0x00FF0000) { avctx.pix_fmt = (alpha != 0) ? PixelFormat.PIX_FMT_RGBA : PixelFormat.PIX_FMT_RGB0; } else { log.av_log(avctx, log.AV_LOG_ERROR, "Unknown bitfields %0X %0X %0X\n", rgb[0], rgb[1], rgb[2]); return error.AVERROR(error.EINVAL); } } else { avctx.pix_fmt = PixelFormat.PIX_FMT_BGRA; } break; case 24: avctx.pix_fmt = PixelFormat.PIX_FMT_BGR24; break; case 16: if (comp == BiCompression.BMP_RGB) { avctx.pix_fmt = PixelFormat.PIX_FMT_RGB555; } else if (comp == BiCompression.BMP_BITFIELDS) { if (rgb[0] == 0xF800 && rgb[1] == 0x07E0 && rgb[2] == 0x001F) avctx.pix_fmt = PixelFormat.PIX_FMT_RGB565; else if (rgb[0] == 0x7C00 && rgb[1] == 0x03E0 && rgb[2] == 0x001F) avctx.pix_fmt = PixelFormat.PIX_FMT_RGB555; else if (rgb[0] == 0x0F00 && rgb[1] == 0x00F0 && rgb[2] == 0x000F) avctx.pix_fmt = PixelFormat.PIX_FMT_RGB444; else { log.av_log(avctx, log.AV_LOG_ERROR, "Unknown bitfields %0X %0X %0X\n", rgb[0], rgb[1], rgb[2]); return error.AVERROR(error.EINVAL); } } break; case 8: if (hsize - ihsize - 14 > 0) { avctx.pix_fmt = PixelFormat.PIX_FMT_PAL8; } else { avctx.pix_fmt = PixelFormat.PIX_FMT_GRAY8; } break; case 1: case 4: if (hsize - ihsize - 14 > 0) { avctx.pix_fmt = PixelFormat.PIX_FMT_PAL8; } else { log.av_log(avctx, log.AV_LOG_ERROR, "Unknown palette for %d-colour BMP\n", 1 << depth); return -1; } break; default: log.av_log(avctx, log.AV_LOG_ERROR, "depth %d not supported\n", depth); return -1; } if (avctx.pix_fmt == PixelFormat.PIX_FMT_NONE) { log.av_log(avctx, log.AV_LOG_ERROR, "unsupported pixel format\n"); return -1; } if (!p.data[0].IsNull) avctx.release_buffer(avctx, p); p.reference = 0; if (avctx.get_buffer(avctx, p) < 0) { log.av_log(avctx, log.AV_LOG_ERROR, "get_buffer() failed\n"); return -1; } p.pict_type = AVPictureType.AV_PICTURE_TYPE_I; p.key_frame = 1; buf = buf0 + hsize; dsize = (int)(buf_size - hsize); /* Line size in file multiple of 4 */ n = (int)(((avctx.width * depth + 31) / 8) & ~3); if (n * avctx.height > dsize && comp != BiCompression.BMP_RLE4 && comp != BiCompression.BMP_RLE8) { log.av_log(avctx, log.AV_LOG_ERROR, "not enough data (%d < %d)\n", dsize, n * avctx.height); return -1; } // RLE may skip decoding some picture areas, so blank picture before decoding if (comp == BiCompression.BMP_RLE4 || comp == BiCompression.BMP_RLE8) { CLib.memset(p.data[0], 0, avctx.height * p.linesize[0]); } if (depth == 4 || depth == 8) { CLib.memset(p.data[1], 0, 1024); } if (height > 0) { ptr = p.data[0] + (avctx.height - 1) * p.linesize[0]; linesize = -p.linesize[0]; } else { ptr = p.data[0]; linesize = p.linesize[0]; } if (avctx.pix_fmt == PixelFormat.PIX_FMT_PAL8) { int colors = (1 << depth); if (ihsize >= 36) { int t; buf = buf0 + 46; t = (int)bytestream.get_le32(ref buf); if (t < 0 || t > (int)(1 << depth)) { log.av_log(avctx, log.AV_LOG_ERROR, "Incorrect number of colors - %X for bitdepth %d\n", t, depth); } else if (t != 0) { colors = t; } } buf = buf0 + 14 + ihsize; //palette location if ((hsize - ihsize - 14) < (colors << 2)) // OS/2 bitmap, 3 bytes per palette entry { for (i = 0; i < colors; i++) { var a = p.data[1].CastPointer<uint>(); a[i] = (uint)((0xff << 24) | bytestream.get_le24(ref buf)); } } else { for (i = 0; i < colors; i++) { var a = p.data[1].CastPointer<uint>(); a[i] = (uint)((0xFFU << 24) | bytestream.get_le32(ref buf)); } } buf = buf0 + hsize; } if (comp == BiCompression.BMP_RLE4 || comp == BiCompression.BMP_RLE8) { if (height < 0) { p.data[0] += p.linesize[0] * (avctx.height - 1); p.linesize[0] = -p.linesize[0]; } //ff_msrle_decode(avctx, (AVPicture)p, depth, buf, dsize); Unimplemented.Mark(); if (height < 0) { p.data[0] += p.linesize[0] * (avctx.height - 1); p.linesize[0] = -p.linesize[0]; } } else { switch (depth) { case 1: for (i = 0; i < avctx.height; i++) { for (int j = 0; j < n; j++) { ptr[j * 8 + 0] = (byte)((buf[j] >> 7) ); ptr[j * 8 + 1] = (byte)((buf[j] >> 6) & 1); ptr[j * 8 + 2] = (byte)((buf[j] >> 5) & 1); ptr[j * 8 + 3] = (byte)((buf[j] >> 4) & 1); ptr[j * 8 + 4] = (byte)((buf[j] >> 3) & 1); ptr[j * 8 + 5] = (byte)((buf[j] >> 2) & 1); ptr[j * 8 + 6] = (byte)((buf[j] >> 1) & 1); ptr[j * 8 + 7] = (byte)((buf[j] >> 0) & 1); } buf += n; ptr += linesize; } break; case 8: case 24: case 32: for (i = 0; i < avctx.height; i++) { //Console.WriteLine("i={0}, BytesPerRow={1}, linesize={2}", i, n, linesize); CLib.memcpy(ptr, buf, n); buf += n; ptr += linesize; } break; case 4: for(i = 0; i < avctx.height; i++){ for(int j = 0; j < n; j++) { ptr[j * 2 + 0] = (byte)((buf[j] >> 4) & 0xF); ptr[j * 2 + 1] = (byte)(buf[j] & 0xF); } buf += n; ptr += linesize; } break; case 16: for (i = 0; i < avctx.height; i++) { Pointer<ushort> src = buf.CastPointer<ushort>(); Pointer<ushort> dst = ptr.CastPointer<ushort>(); for (int j = 0; j < avctx.width; j++) { dst[0] = av_bswap.av_le2ne16(src[0]); src++; dst++; } buf += n; ptr += linesize; } break; default: log.av_log(avctx, log.AV_LOG_ERROR, "BMP decoder is broken\n"); return -1; } } outputData = s.picture; return buf_size; } // decode
public override int decode(AVCodecContext avctx, ref object outdata, AVPacket avpkt) { outdata = null; TargaContext s = (TargaContext)avctx.priv_data; //AVFrame *picture = data; AVFrame p = s.picture; Pointer<byte> dst; int stride; TargaCompr compr; int idlen, pal, y, w, h, bpp, flags; int first_clr, colors, csize; bytestream2.init(ref s.gb, avpkt.data, avpkt.size); /* parse image header */ idlen = bytestream2.get_byte(ref s.gb); pal = bytestream2.get_byte(ref s.gb); compr = (TargaCompr)bytestream2.get_byte(ref s.gb); first_clr = bytestream2.get_le16(ref s.gb); colors = bytestream2.get_le16(ref s.gb); csize = bytestream2.get_byte(ref s.gb); bytestream2.skip(ref s.gb, 4); /* 2: x, 2: y */ w = bytestream2.get_le16(ref s.gb); h = bytestream2.get_le16(ref s.gb); bpp = bytestream2.get_byte(ref s.gb); if (bytestream2.get_bytes_left(ref s.gb) <= idlen) { log.av_log(avctx, log.AV_LOG_ERROR, "Not enough data to read header\n"); return error.AVERROR_INVALIDDATA; } flags = bytestream2.get_byte(ref s.gb); if ((pal == 0) && ((first_clr != 0) || (colors != 0) || (csize != 0))) { log.av_log(avctx, log.AV_LOG_WARNING, "File without colormap has colormap information set.\n"); // specification says we should ignore those value in this case first_clr = colors = csize = 0; } // skip identifier if any bytestream2.skip(ref s.gb, idlen); switch(bpp){ case 8: avctx.pix_fmt = ((TargaCompr)((int)compr & (~(int)TargaCompr.TGA_RLE)) == TargaCompr.TGA_BW) ? PixelFormat.PIX_FMT_GRAY8 : PixelFormat.PIX_FMT_PAL8; break; case 15: case 16: avctx.pix_fmt = PixelFormat.PIX_FMT_RGB555LE; break; case 24: avctx.pix_fmt = PixelFormat.PIX_FMT_BGR24; break; case 32: avctx.pix_fmt = PixelFormat.PIX_FMT_BGRA; break; default: log.av_log(avctx, log.AV_LOG_ERROR, "Bit depth %i is not supported\n", bpp); return -1; } if (!s.picture.data[0].IsNull) avctx.release_buffer(avctx, s.picture); if (imgutils.av_image_check_size((uint)w, (uint)h, 0, avctx) != 0) return -1; if (w != avctx.width || h != avctx.height) Functions.avcodec_set_dimensions(avctx, w, h); if (avctx.get_buffer(avctx, p) < 0) { log.av_log(avctx, log.AV_LOG_ERROR, "get_buffer() failed\n"); return -1; } if ((flags & 0x20) != 0) { dst = p.data[0]; stride = p.linesize[0]; } else { //image is upside-down dst = p.data[0] + p.linesize[0] * (h - 1); stride = -p.linesize[0]; } if (colors != 0) { int pal_size, pal_sample_size; if((colors + first_clr) > 256){ log.av_log(avctx, log.AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr); return -1; } switch (csize) { case 24: pal_sample_size = 3; break; case 16: case 15: pal_sample_size = 2; break; default: log.av_log(avctx, log.AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize); return -1; } pal_size = colors * pal_sample_size; if (avctx.pix_fmt != PixelFormat.PIX_FMT_PAL8) { //should not occur but skip palette anyway bytestream2.skip(ref s.gb, pal_size); } else { int t; var ppal = p.data[1].CastPointer<uint>() + first_clr; if (bytestream2.get_bytes_left(ref s.gb) < pal_size) { log.av_log(avctx, log.AV_LOG_ERROR, "Not enough data to read palette\n"); return error.AVERROR_INVALIDDATA; } switch (pal_sample_size) { case 3: /* RGB24 */ for (t = 0; t < colors; t++) { ppal[0] = (0xffU << 24) | bytestream2.get_le24u(ref s.gb); ppal++; } break; case 2: /* RGB555 */ for (t = 0; t < colors; t++) { var v = (uint)bytestream2.get_le16u(ref s.gb); v = ((v & 0x7C00) << 9) | ((v & 0x03E0) << 6) | ((v & 0x001F) << 3); /* left bit replication */ v |= (v & 0xE0E0E0U) >> 5; ppal[0] = (0xffU << 24) | v; ppal++; } break; } p.palette_has_changed = 1; } } if ((compr & (~TargaCompr.TGA_RLE)) == TargaCompr.TGA_NODATA) { CLib.memset(p.data[0], 0, p.linesize[0] * h); } else { if ((compr & TargaCompr.TGA_RLE) != 0) { //int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp); //if (res < 0) return res; throw (new NotImplementedException()); } else { var img_size = w * ((bpp + 1) >> 3); if (bytestream2.get_bytes_left(ref s.gb) < img_size * h) { log.av_log(avctx, log.AV_LOG_ERROR, "Not enough data available for image\n"); return error.AVERROR_INVALIDDATA; } for (y = 0; y < h; y++) { bytestream2.get_bufferu(ref s.gb, dst, img_size); dst += stride; } } } if ((flags & 0x10) != 0) // right-to-left, needs horizontal flip { int x; for(y = 0; y < h; y++){ var line = p.data[0].GetOffsetPointer(y * p.linesize[0]); for (x = 0; x < w >> 1; x++) { switch (bpp) { case 32: line.CastPointer<uint>().SwapValuesAtOffsets((x), (w - x - 1)); break; case 24: line.CastPointer<byte>().SwapValuesAtOffsets((3 * x + 0), (3 * w - 3 * x - 3)); line.CastPointer<byte>().SwapValuesAtOffsets((3 * x + 1), (3 * w - 3 * x - 2)); line.CastPointer<byte>().SwapValuesAtOffsets((3 * x + 2), (3 * w - 3 * x - 1)); break; case 16: line.CastPointer<ushort>().SwapValuesAtOffsets((x), (w -x - 1)); break; case 8: line.CastPointer<byte>().SwapValuesAtOffsets((x), (w -x - 1)); break; } } } } outdata = s.picture; return avpkt.size; }