static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic, int depth, GetByteContext *gb) { uint8_t *output, *output_end; int p1, p2, line=avctx->height - 1, pos=0, i; uint16_t pix16; uint32_t pix32; unsigned int width= FFABS(pic->linesize[0]) / (depth >> 3); output = pic->data[0] + (avctx->height - 1) * pic->linesize[0]; output_end = pic->data[0] + avctx->height * pic->linesize[0]; while (bytestream2_get_bytes_left(gb) > 0) { p1 = bytestream2_get_byteu(gb); if(p1 == 0) { //Escape code p2 = bytestream2_get_byte(gb); if(p2 == 0) { //End-of-line if (--line < 0) { if (bytestream2_get_be16(gb) == 1) { // end-of-picture return 0; } else { av_log(avctx, AV_LOG_ERROR, "Next line is beyond picture bounds (%d bytes left)\n", bytestream2_get_bytes_left(gb)); return AVERROR_INVALIDDATA; } } output = pic->data[0] + line * pic->linesize[0]; pos = 0; continue; } else if(p2 == 1) { //End-of-picture return 0; } else if(p2 == 2) { //Skip p1 = bytestream2_get_byte(gb); p2 = bytestream2_get_byte(gb); line -= p2; pos += p1; if (line < 0 || pos >= width){ av_log(avctx, AV_LOG_ERROR, "Skip beyond picture bounds\n"); return -1; } output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3); continue; } // Copy data if ((pic->linesize[0] > 0 && output + p2 * (depth >> 3) > output_end) || (pic->linesize[0] < 0 && output + p2 * (depth >> 3) < output_end)) { bytestream2_skip(gb, 2 * (depth >> 3)); continue; } else if (bytestream2_get_bytes_left(gb) < p2 * (depth >> 3)) { av_log(avctx, AV_LOG_ERROR, "bytestream overrun\n"); return AVERROR_INVALIDDATA; } if ((depth == 8) || (depth == 24)) { for(i = 0; i < p2 * (depth >> 3); i++) { *output++ = bytestream2_get_byteu(gb); } // RLE8 copy is actually padded - and runs are not! if(depth == 8 && (p2 & 1)) { bytestream2_skip(gb, 1); } } else if (depth == 16) { for(i = 0; i < p2; i++) { *(uint16_t*)output = bytestream2_get_le16u(gb); output += 2; } } else if (depth == 32) { for(i = 0; i < p2; i++) { *(uint32_t*)output = bytestream2_get_le32u(gb); output += 4; } } pos += p2; } else { //run of pixels uint8_t pix[3]; //original pixel if ((pic->linesize[0] > 0 && output + p1 * (depth >> 3) > output_end) || (pic->linesize[0] < 0 && output + p1 * (depth >> 3) < output_end)) continue; switch(depth){ case 8: pix[0] = bytestream2_get_byte(gb); for(i = 0; i < p1; i++) *output++ = pix[0]; break; case 16: pix16 = bytestream2_get_le16(gb); for(i = 0; i < p1; i++) { *(uint16_t*)output = pix16; output += 2; } break; case 24: pix[0] = bytestream2_get_byte(gb); pix[1] = bytestream2_get_byte(gb); pix[2] = bytestream2_get_byte(gb); for(i = 0; i < p1; i++) { *output++ = pix[0]; *output++ = pix[1]; *output++ = pix[2]; } break; case 32: pix32 = bytestream2_get_le32(gb); for(i = 0; i < p1; i++) { *(uint32_t*)output = pix32; output += 4; } break; } pos += p1; } } av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no end-of-picture code\n"); return 0; }