Revision e00f41d5

View differences:

Changelog
76 76
- IVF muxer added
77 77
- Wing Commander IV movies decoder added
78 78
- movie source added
79
- Bink version 'b' video decoder
79 80

  
80 81

  
81 82
version 0.6:
doc/general.texi
352 352
@item Bethesda VID video     @tab     @tab  X
353 353
    @tab Used in some games from Bethesda Softworks.
354 354
@item Bink Video             @tab     @tab  X
355
    @tab Support for version 'b' is missing.
356 355
@item Brute Force & Ignorance   @tab   @tab X
357 356
    @tab Used in the game Flash Traffic: City of Angels.
358 357
@item C93 video              @tab     @tab  X
libavcodec/avcodec.h
33 33

  
34 34
#define LIBAVCODEC_VERSION_MAJOR 52
35 35
#define LIBAVCODEC_VERSION_MINOR 112
36
#define LIBAVCODEC_VERSION_MICRO  0
36
#define LIBAVCODEC_VERSION_MICRO  1
37 37

  
38 38
#define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
39 39
                                               LIBAVCODEC_VERSION_MINOR, \
libavcodec/bink.c
1 1
/*
2 2
 * Bink video decoder
3 3
 * Copyright (c) 2009 Konstantin Shishkov
4
 * Copyright (C) 2011 Peter Ross <pross@xvid.org>
4 5
 *
5 6
 * This file is part of FFmpeg.
6 7
 *
......
34 35
static VLC bink_trees[16];
35 36

  
36 37
/**
38
 * IDs for different data types used in old version of Bink video codec
39
 */
40
enum OldSources {
41
    BINKB_SRC_BLOCK_TYPES = 0, ///< 8x8 block types
42
    BINKB_SRC_COLORS,          ///< pixel values used for different block types
43
    BINKB_SRC_PATTERN,         ///< 8-bit values for 2-colour pattern fill
44
    BINKB_SRC_X_OFF,           ///< X components of motion value
45
    BINKB_SRC_Y_OFF,           ///< Y components of motion value
46
    BINKB_SRC_INTRA_DC,        ///< DC values for intrablocks with DCT
47
    BINKB_SRC_INTER_DC,        ///< DC values for interblocks with DCT
48
    BINKB_SRC_INTRA_Q,         ///< quantizer values for intrablocks with DCT
49
    BINKB_SRC_INTER_Q,         ///< quantizer values for interblocks with DCT
50
    BINKB_SRC_INTER_COEFS,     ///< number of coefficients for residue blocks
51

  
52
    BINKB_NB_SRC
53
};
54

  
55
static const int binkb_bundle_sizes[BINKB_NB_SRC] = {
56
    4, 8, 8, 5, 5, 11, 11, 4, 4, 7
57
};
58

  
59
static const int binkb_bundle_signed[BINKB_NB_SRC] = {
60
    0, 0, 0, 1, 1, 0, 1, 0, 0, 0
61
};
62

  
63
static uint32_t binkb_intra_quant[16][64];
64
static uint32_t binkb_inter_quant[16][64];
65

  
66
/**
37 67
 * IDs for different data types used in Bink video codec
38 68
 */
39 69
enum Sources {
......
85 115
    int            swap_planes;
86 116
    ScanTable      scantable;            ///< permutated scantable for DCT coeffs decoding
87 117

  
88
    Bundle         bundle[BINK_NB_SRC];  ///< bundles for decoding all data types
118
    Bundle         bundle[BINKB_NB_SRC]; ///< bundles for decoding all data types
89 119
    Tree           col_high[16];         ///< trees for decoding high nibble in "colours" data type
90 120
    int            col_lastval;          ///< value of last decoded high nibble in "colours" data type
91 121
} BinkContext;
......
145 175
    bh = (c->avctx->height + 7) >> 3;
146 176
    blocks = bw * bh;
147 177

  
148
    for (i = 0; i < BINK_NB_SRC; i++) {
178
    for (i = 0; i < BINKB_NB_SRC; i++) {
149 179
        c->bundle[i].data = av_malloc(blocks * 64);
150 180
        c->bundle[i].data_end = c->bundle[i].data + blocks * 64;
151 181
    }
......
159 189
static av_cold void free_bundles(BinkContext *c)
160 190
{
161 191
    int i;
162
    for (i = 0; i < BINK_NB_SRC; i++)
192
    for (i = 0; i < BINKB_NB_SRC; i++)
163 193
        av_freep(&c->bundle[i].data);
164 194
}
165 195

  
......
470 500
 */
471 501
static inline int get_value(BinkContext *c, int bundle)
472 502
{
473
    int16_t ret;
503
    int ret;
474 504

  
475 505
    if (bundle < BINK_SRC_X_OFF || bundle == BINK_SRC_RUN)
476 506
        return *c->bundle[bundle].cur_ptr++;
......
481 511
    return ret;
482 512
}
483 513

  
514
static void binkb_init_bundle(BinkContext *c, int bundle_num)
515
{
516
    c->bundle[bundle_num].cur_dec =
517
    c->bundle[bundle_num].cur_ptr = c->bundle[bundle_num].data;
518
    c->bundle[bundle_num].len = 13;
519
}
520

  
521
static void binkb_init_bundles(BinkContext *c)
522
{
523
    int i;
524
    for (i = 0; i < BINKB_NB_SRC; i++)
525
        binkb_init_bundle(c, i);
526
}
527

  
528
static int binkb_read_bundle(BinkContext *c, GetBitContext *gb, int bundle_num)
529
{
530
    const int bits = binkb_bundle_sizes[bundle_num];
531
    const int mask = 1 << (bits - 1);
532
    const int issigned = binkb_bundle_signed[bundle_num];
533
    Bundle *b = &c->bundle[bundle_num];
534
    int i, len;
535

  
536
    CHECK_READ_VAL(gb, b, len);
537
    if (bits <= 8) {
538
        if (!issigned) {
539
            for (i = 0; i < len; i++)
540
                *b->cur_dec++ = get_bits(gb, bits);
541
        } else {
542
            for (i = 0; i < len; i++)
543
                *b->cur_dec++ = get_bits(gb, bits) - mask;
544
        }
545
    } else {
546
        int16_t *dst = (int16_t*)b->cur_dec;
547

  
548
        if (!issigned) {
549
            for (i = 0; i < len; i++)
550
                *dst++ = get_bits(gb, bits);
551
        } else {
552
            for (i = 0; i < len; i++)
553
                *dst++ = get_bits(gb, bits) - mask;
554
        }
555
        b->cur_dec = (uint8_t*)dst;
556
    }
557
    return 0;
558
}
559

  
560
static inline int binkb_get_value(BinkContext *c, int bundle_num)
561
{
562
    int16_t ret;
563
    const int bits = binkb_bundle_sizes[bundle_num];
564

  
565
    if (bits <= 8) {
566
        int val = *c->bundle[bundle_num].cur_ptr++;
567
        return binkb_bundle_signed[bundle_num] ? (int8_t)val : val;
568
    }
569
    ret = *(int16_t*)c->bundle[bundle_num].cur_ptr;
570
    c->bundle[bundle_num].cur_ptr += 2;
571
    return ret;
572
}
573

  
574
typedef const uint32_t quant_matrices[16][64];
575
static const quant_matrices * bink_quant_matrices[2][2] = {
576
    { &bink_inter_quant,  &bink_intra_quant  },
577
    { &binkb_inter_quant, &binkb_intra_quant },
578
};
579

  
484 580
/**
485 581
 * Read 8x8 block of DCT coefficients.
486 582
 *
487 583
 * @param gb       context for reading bits
488 584
 * @param block    place for storing coefficients
489 585
 * @param scan     scan order table
586
 * @param is_binkb use version 'b' quantizer matrices
490 587
 * @param is_intra tells what set of quantizer matrices to use
491 588
 * @return 0 for success, negative value in other cases
492 589
 */
493 590
static int read_dct_coeffs(GetBitContext *gb, DCTELEM block[64], const uint8_t *scan,
494
                           int is_intra)
591
                           int is_binkb, int is_intra, int q)
495 592
{
496 593
    int coef_list[128];
497 594
    int mode_list[128];
......
571 668
        }
572 669
    }
573 670

  
574
    quant_idx = get_bits(gb, 4);
575
    quant = is_intra ? bink_intra_quant[quant_idx]
576
                     : bink_inter_quant[quant_idx];
671
    if (q == -1) {
672
        quant_idx = get_bits(gb, 4);
673
    } else {
674
        quant_idx = q;
675
    }
676

  
677
    quant = (*bink_quant_matrices[is_binkb][is_intra])[quant_idx];
678

  
577 679
    block[0] = (block[0] * quant[0]) >> 11;
578 680
    for (i = 0; i < coef_count; i++) {
579 681
        int idx = coef_idx[i];
......
673 775
    return 0;
674 776
}
675 777

  
778
/**
779
 * Copy 8x8 block from source to destination, where src and dst may be overlapped
780
 */
781
static inline void put_pixels8x8_overlapped(uint8_t *dst, uint8_t *src, int stride)
782
{
783
    uint8_t tmp[64];
784
    int i;
785
    for (i = 0; i < 8; i++)
786
        memcpy(tmp + i*8, src + i*stride, 8);
787
    for (i = 0; i < 8; i++)
788
        memcpy(dst + i*stride, tmp + i*8, 8);
789
}
790

  
791
static int binkb_decode_plane(BinkContext *c, GetBitContext *gb, int plane_idx,
792
                              int is_key, int is_chroma)
793
{
794
    int blk;
795
    int i, j, bx, by;
796
    uint8_t *dst, *ref, *ref_start, *ref_end;
797
    int v, col[2];
798
    const uint8_t *scan;
799
    int xoff, yoff;
800
    DECLARE_ALIGNED(16, DCTELEM, block[64]);
801
    int coordmap[64];
802
    int ybias = is_key ? -15 : 0;
803
    int qp;
804

  
805
    const int stride = c->pic.linesize[plane_idx];
806
    int bw = is_chroma ? (c->avctx->width  + 15) >> 4 : (c->avctx->width  + 7) >> 3;
807
    int bh = is_chroma ? (c->avctx->height + 15) >> 4 : (c->avctx->height + 7) >> 3;
808

  
809
    binkb_init_bundles(c);
810
    ref_start = c->pic.data[plane_idx];
811
    ref_end   = c->pic.data[plane_idx] + (bh * c->pic.linesize[plane_idx] + bw) * 8;
812

  
813
    for (i = 0; i < 64; i++)
814
        coordmap[i] = (i & 7) + (i >> 3) * stride;
815

  
816
    for (by = 0; by < bh; by++) {
817
        for (i = 0; i < BINKB_NB_SRC; i++) {
818
            if (binkb_read_bundle(c, gb, i) < 0)
819
                return -1;
820
        }
821

  
822
        dst  = c->pic.data[plane_idx]  + 8*by*stride;
823
        for (bx = 0; bx < bw; bx++, dst += 8) {
824
            blk = binkb_get_value(c, BINKB_SRC_BLOCK_TYPES);
825
            switch (blk) {
826
            case 0:
827
                break;
828
            case 1:
829
                scan = bink_patterns[get_bits(gb, 4)];
830
                i = 0;
831
                do {
832
                    int mode, run;
833

  
834
                    mode = get_bits1(gb);
835
                    run = get_bits(gb, binkb_runbits[i]) + 1;
836

  
837
                    i += run;
838
                    if (i > 64) {
839
                        av_log(c->avctx, AV_LOG_ERROR, "Run went out of bounds\n");
840
                        return -1;
841
                    }
842
                    if (mode) {
843
                        v = binkb_get_value(c, BINKB_SRC_COLORS);
844
                        for (j = 0; j < run; j++)
845
                            dst[coordmap[*scan++]] = v;
846
                    } else {
847
                        for (j = 0; j < run; j++)
848
                            dst[coordmap[*scan++]] = binkb_get_value(c, BINKB_SRC_COLORS);
849
                    }
850
                } while (i < 63);
851
                if (i == 63)
852
                    dst[coordmap[*scan++]] = binkb_get_value(c, BINKB_SRC_COLORS);
853
                break;
854
            case 2:
855
                c->dsp.clear_block(block);
856
                block[0] = binkb_get_value(c, BINKB_SRC_INTRA_DC);
857
                qp = binkb_get_value(c, BINKB_SRC_INTRA_Q);
858
                read_dct_coeffs(gb, block, c->scantable.permutated, 1, 1, qp);
859
                c->dsp.idct_put(dst, stride, block);
860
                break;
861
            case 3:
862
                xoff = binkb_get_value(c, BINKB_SRC_X_OFF);
863
                yoff = binkb_get_value(c, BINKB_SRC_Y_OFF) + ybias;
864
                ref = dst + xoff + yoff * stride;
865
                if (ref < ref_start || ref + 8*stride > ref_end) {
866
                    av_log(c->avctx, AV_LOG_WARNING, "Reference block is out of bounds\n");
867
                } else if (ref + 8*stride < dst || ref >= dst + 8*stride) {
868
                    c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
869
                } else {
870
                    put_pixels8x8_overlapped(dst, ref, stride);
871
                }
872
                c->dsp.clear_block(block);
873
                v = binkb_get_value(c, BINKB_SRC_INTER_COEFS);
874
                read_residue(gb, block, v);
875
                c->dsp.add_pixels8(dst, block, stride);
876
                break;
877
            case 4:
878
                xoff = binkb_get_value(c, BINKB_SRC_X_OFF);
879
                yoff = binkb_get_value(c, BINKB_SRC_Y_OFF) + ybias;
880
                ref = dst + xoff + yoff * stride;
881
                if (ref < ref_start || ref + 8 * stride > ref_end) {
882
                    av_log(c->avctx, AV_LOG_WARNING, "Reference block is out of bounds\n");
883
                } else if (ref + 8*stride < dst || ref >= dst + 8*stride) {
884
                    c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
885
                } else {
886
                    put_pixels8x8_overlapped(dst, ref, stride);
887
                }
888
                c->dsp.clear_block(block);
889
                block[0] = binkb_get_value(c, BINKB_SRC_INTER_DC);
890
                qp = binkb_get_value(c, BINKB_SRC_INTER_Q);
891
                read_dct_coeffs(gb, block, c->scantable.permutated, 1, 0, qp);
892
                c->dsp.idct_add(dst, stride, block);
893
                break;
894
            case 5:
895
                v = binkb_get_value(c, BINKB_SRC_COLORS);
896
                c->dsp.fill_block_tab[1](dst, v, stride, 8);
897
                break;
898
            case 6:
899
                for (i = 0; i < 2; i++)
900
                    col[i] = binkb_get_value(c, BINKB_SRC_COLORS);
901
                for (i = 0; i < 8; i++) {
902
                    v = binkb_get_value(c, BINKB_SRC_PATTERN);
903
                    for (j = 0; j < 8; j++, v >>= 1)
904
                        dst[i*stride + j] = col[v & 1];
905
                }
906
                break;
907
            case 7:
908
                xoff = binkb_get_value(c, BINKB_SRC_X_OFF);
909
                yoff = binkb_get_value(c, BINKB_SRC_Y_OFF) + ybias;
910
                ref = dst + xoff + yoff * stride;
911
                if (ref < ref_start || ref + 8 * stride > ref_end) {
912
                    av_log(c->avctx, AV_LOG_WARNING, "Reference block is out of bounds\n");
913
                } else if (ref + 8*stride < dst || ref >= dst + 8*stride) {
914
                    c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
915
                } else {
916
                    put_pixels8x8_overlapped(dst, ref, stride);
917
                }
918
                break;
919
            case 8:
920
                for (i = 0; i < 8; i++)
921
                    memcpy(dst + i*stride, c->bundle[BINKB_SRC_COLORS].cur_ptr + i*8, 8);
922
                c->bundle[BINKB_SRC_COLORS].cur_ptr += 64;
923
                break;
924
            default:
925
                av_log(c->avctx, AV_LOG_ERROR, "Unknown block type %d\n", blk);
926
                return -1;
927
            }
928
        }
929
    }
930
    if (get_bits_count(gb) & 0x1F) //next plane data starts at 32-bit boundary
931
        skip_bits_long(gb, 32 - (get_bits_count(gb) & 0x1F));
932

  
933
    return 0;
934
}
935

  
676 936
static int bink_decode_plane(BinkContext *c, GetBitContext *gb, int plane_idx,
677 937
                             int is_chroma)
678 938
{
......
768 1028
                case INTRA_BLOCK:
769 1029
                    c->dsp.clear_block(block);
770 1030
                    block[0] = get_value(c, BINK_SRC_INTRA_DC);
771
                    read_dct_coeffs(gb, block, c->scantable.permutated, 1);
1031
                    read_dct_coeffs(gb, block, c->scantable.permutated, 0, 1, -1);
772 1032
                    c->dsp.idct(block);
773 1033
                    c->dsp.put_pixels_nonclamped(block, ublock, 8);
774 1034
                    break;
......
852 1112
            case INTRA_BLOCK:
853 1113
                c->dsp.clear_block(block);
854 1114
                block[0] = get_value(c, BINK_SRC_INTRA_DC);
855
                read_dct_coeffs(gb, block, c->scantable.permutated, 1);
1115
                read_dct_coeffs(gb, block, c->scantable.permutated, 0, 1, -1);
856 1116
                c->dsp.idct_put(dst, stride, block);
857 1117
                break;
858 1118
            case FILL_BLOCK:
......
866 1126
                c->dsp.put_pixels_tab[1][0](dst, ref, stride, 8);
867 1127
                c->dsp.clear_block(block);
868 1128
                block[0] = get_value(c, BINK_SRC_INTER_DC);
869
                read_dct_coeffs(gb, block, c->scantable.permutated, 0);
1129
                read_dct_coeffs(gb, block, c->scantable.permutated, 0, 0, -1);
870 1130
                c->dsp.idct_add(dst, stride, block);
871 1131
                break;
872 1132
            case PATTERN_BLOCK:
......
902 1162
    int plane, plane_idx;
903 1163
    int bits_count = pkt->size << 3;
904 1164

  
1165
    if (c->version > 'b') {
905 1166
    if(c->pic.data[0])
906 1167
        avctx->release_buffer(avctx, &c->pic);
907 1168

  
......
909 1170
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
910 1171
        return -1;
911 1172
    }
1173
    } else {
1174
        if(avctx->reget_buffer(avctx, &c->pic) < 0){
1175
            av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
1176
            return -1;
1177
        }
1178
    }
912 1179

  
913 1180
    init_get_bits(&gb, pkt->data, bits_count);
914 1181
    if (c->has_alpha) {
......
923 1190
    for (plane = 0; plane < 3; plane++) {
924 1191
        plane_idx = (!plane || !c->swap_planes) ? plane : (plane ^ 3);
925 1192

  
926
        if (bink_decode_plane(c, &gb, plane_idx, !!plane) < 0)
927
            return -1;
1193
        if (c->version > 'b') {
1194
            if (bink_decode_plane(c, &gb, plane_idx, !!plane) < 0)
1195
                return -1;
1196
        } else {
1197
            if (binkb_decode_plane(c, &gb, plane_idx, !pkt->pts, !!plane) < 0)
1198
                return -1;
1199
        }
928 1200
        if (get_bits_count(&gb) >= bits_count)
929 1201
            break;
930 1202
    }
......
933 1205
    *data_size = sizeof(AVFrame);
934 1206
    *(AVFrame*)data = c->pic;
935 1207

  
936
    FFSWAP(AVFrame, c->pic, c->last);
1208
    if (c->version > 'b')
1209
        FFSWAP(AVFrame, c->pic, c->last);
937 1210

  
938 1211
    /* always report that the buffer was completely consumed */
939 1212
    return pkt->size;
940 1213
}
941 1214

  
1215
/**
1216
 * Caclulate quantization tables for version b
1217
 */
1218
static av_cold void binkb_calc_quant()
1219
{
1220
    float s[64];
1221
    int i, j;
1222

  
1223
    for (j = 0; j < 8; j++) {
1224
        for (i = 0; i < 8; i++) {
1225
            if (j && j != 4)
1226
               if (i && i != 4)
1227
                   s[j*8 + i] = cos(j * M_PI/16.0f) * cos(i * M_PI/16.0f) * 2.0f;
1228
               else
1229
                   s[j*8 + i] = cos(j * M_PI/16.0f) * sqrt(2.0f);
1230
            else
1231
               if (i && i != 4)
1232
                   s[j*8 + i] = cos(i * M_PI/16.0f) * sqrt(2.0f);
1233
               else
1234
                   s[j*8 + i] = 1.0f;
1235
        }
1236
    }
1237

  
1238
    for (j = 0; j < 16; j++) {
1239
        for (i = 0; i < 64; i++) {
1240
            binkb_intra_quant[j][i] = (1L << 12) * binkb_intra_seed[i] * s[i] *
1241
                                      binkb_num[j]/(float)binkb_den[j];
1242
            binkb_inter_quant[j][i] = (1L << 12) * binkb_inter_seed[i] * s[i] *
1243
                                      binkb_num[j]/(float)binkb_den[j];
1244
        }
1245
    }
1246
}
1247

  
942 1248
static av_cold int decode_init(AVCodecContext *avctx)
943 1249
{
944 1250
    BinkContext * const c = avctx->priv_data;
945 1251
    static VLC_TYPE table[16 * 128][2];
1252
    static int binkb_initialised = 0;
946 1253
    int i;
947 1254
    int flags;
948 1255

  
949 1256
    c->version = avctx->codec_tag >> 24;
950
    if (c->version < 'c') {
951
        av_log(avctx, AV_LOG_ERROR, "Too old version '%c'\n", c->version);
952
        return -1;
953
    }
954 1257
    if (avctx->extradata_size < 4) {
955 1258
        av_log(avctx, AV_LOG_ERROR, "Extradata missing or too short\n");
956 1259
        return -1;
......
984 1287

  
985 1288
    init_bundles(c);
986 1289

  
1290
    if (c->version == 'b') {
1291
        if (!binkb_initialised) {
1292
            binkb_calc_quant();
1293
            binkb_initialised = 1;
1294
        }
1295
    }
1296

  
987 1297
    return 0;
988 1298
}
989 1299

  
libavcodec/binkdata.h
611 611
},
612 612
};
613 613

  
614
static const uint8_t binkb_runbits[64] = {
615
    6, 6, 6, 6, 6, 6, 6, 6,
616
    6, 6, 6, 6, 6, 6, 6, 6,
617
    6, 6, 6, 6, 6, 6, 6, 6,
618
    6, 6, 6, 6, 6, 6, 6, 6,
619
    5, 5, 5, 5, 5, 5, 5, 5,
620
    5, 5, 5, 5, 5, 5, 5, 5,
621
    4, 4, 4, 4, 4, 4, 4, 4,
622
    3, 3, 3, 3, 2, 2, 1, 0,
623
};
624

  
625
static const uint8_t binkb_intra_seed[64] = {
626
    16, 16, 16, 19, 16, 19, 22, 22,
627
    22, 22, 26, 24, 26, 22, 22, 27,
628
    27, 27, 26, 26, 26, 29, 29, 29,
629
    27, 27, 27, 26, 34, 34, 34, 29,
630
    29, 29, 27, 27, 37, 34, 34, 32,
631
    32, 29, 29, 38, 37, 35, 35, 34,
632
    35, 40, 40, 40, 38, 38, 48, 48,
633
    46, 46, 58, 56, 56, 69, 69, 83,
634
};
635

  
636
static const uint8_t binkb_inter_seed[64] = {
637
    16, 17, 17, 18, 18, 18, 19, 19,
638
    19, 19, 20, 20, 20, 20, 20, 21,
639
    21, 21, 21, 21, 21, 22, 22, 22,
640
    22, 22, 22, 22, 23, 23, 23, 23,
641
    23, 23, 23, 23, 24, 24, 24, 25,
642
    24, 24, 24, 25, 26, 26, 26, 26,
643
    25, 27, 27, 27, 27, 27, 28, 28,
644
    28, 28, 30, 30, 30, 31, 31, 33,
645
};
646

  
647
static const uint8_t binkb_num[16] = {
648
    1, 4, 5, 2, 7, 8, 3, 7, 4, 9, 5, 6, 7, 8, 9, 10
649
};
650

  
651
static const uint8_t binkb_den[16] = {
652
    1, 3, 3, 1, 3, 3, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1
653
};
654

  
614 655
#endif /* AVCODEC_BINKDATA_H */

Also available in: Unified diff