]> git.sesse.net Git - ffmpeg/commitdiff
Merge remote-tracking branch 'qatar/master'
authorMichael Niedermayer <michaelni@gmx.at>
Thu, 5 Apr 2012 20:26:50 +0000 (22:26 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Thu, 5 Apr 2012 20:26:50 +0000 (22:26 +0200)
* qatar/master:
  h264: Factorize declaration of mb_sizes array.
  vsrc_buffer: when no frame is available, return an error instead of segfaulting.
  configure: add dl to frei0r extralibs.
  dsputil x86: use SSE float instruction instead of SSE2 integer equivalent
  dsputil x86: remove deprecated parameter from scalarproduct_int16 prototype
  vp8dsp x86: perform rounding shift with a single instruction
  fate: add BMP tests.
  swscale: handle complete dimensions for monoblack/white.
  aacenc: Mark deinterleave_input_samples argument as const.
  vf_unsharp: Mark readonly variable as const.
  h264: fix 4:2:2 PCM-macroblocks decoding

Conflicts:
configure
libavcodec/h264.h
libavcodec/x86/dsputil_mmx.c
libavfilter/vf_unsharp.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
26 files changed:
configure
libavcodec/aacenc.c
libavcodec/h264.c
libavcodec/h264.h
libavcodec/h264_cabac.c
libavcodec/h264_cavlc.c
libavcodec/x86/dsputil_mmx.c
libavcodec/x86/vp8dsp.asm
libavfilter/vf_unsharp.c
libswscale/input.c
libswscale/output.c
tests/Makefile
tests/fate/bmp.mak [new file with mode: 0644]
tests/ref/fate/bmp-15bit [new file with mode: 0644]
tests/ref/fate/bmp-15bit-mask [new file with mode: 0644]
tests/ref/fate/bmp-16bit-mask [new file with mode: 0644]
tests/ref/fate/bmp-1bit [new file with mode: 0644]
tests/ref/fate/bmp-24bit [new file with mode: 0644]
tests/ref/fate/bmp-32bit [new file with mode: 0644]
tests/ref/fate/bmp-32bit-mask [new file with mode: 0644]
tests/ref/fate/bmp-4bit [new file with mode: 0644]
tests/ref/fate/bmp-4bit-os2 [new file with mode: 0644]
tests/ref/fate/bmp-8bit [new file with mode: 0644]
tests/ref/fate/bmp-8bit-os2 [new file with mode: 0644]
tests/ref/fate/bmp-rle4 [new file with mode: 0644]
tests/ref/fate/bmp-rle8 [new file with mode: 0644]

index 201217569664a9de0a2aeb7ea98038296004419c..c31bf5d916b6d1a74ecc50201a6e80b0e3f150ad 100755 (executable)
--- a/configure
+++ b/configure
@@ -1675,7 +1675,9 @@ cropdetect_filter_deps="gpl"
 delogo_filter_deps="gpl"
 drawtext_filter_deps="libfreetype"
 frei0r_filter_deps="frei0r dlopen"
+frei0r_filter_extralibs='$ldl'
 frei0r_src_filter_deps="frei0r dlopen"
+frei0r_src_filter_extralibs='$ldl'
 hqdn3d_filter_deps="gpl"
 movie_filter_deps="avcodec avformat"
 mp_filter_deps="gpl avcodec swscale postproc"
index fd72dafd17ff4b50539b776619c9b6a37261081f..3ac2ad890dcead90213302f6bdee3c46501b7d5b 100644 (file)
@@ -477,7 +477,7 @@ static void put_bitstream_info(AVCodecContext *avctx, AACEncContext *s,
  * Deinterleave input samples.
  * Channels are reordered from libavcodec's default order to AAC order.
  */
-static void deinterleave_input_samples(AACEncContext *s, AVFrame *frame)
+static void deinterleave_input_samples(AACEncContext *s, const AVFrame *frame)
 {
     int ch, i;
     const int sinc = s->channels;
index fc612905ab05cfe7c83a1af3e4f0ce5d2c71c521..b909600b3ed0060438abb9fc9d5d907f2166eb68 100644 (file)
@@ -48,6 +48,8 @@
 // #undef NDEBUG
 #include <assert.h>
 
+const uint16_t ff_h264_mb_sizes[4] = { 256, 384, 512, 768 };
+
 static const uint8_t rem6[QP_MAX_NUM + 1] = {
     0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2,
     3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
@@ -2126,7 +2128,8 @@ static av_always_inline void hl_decode_mb_internal(H264Context *h, int simple,
         if (pixel_shift) {
             int j;
             GetBitContext gb;
-            init_get_bits(&gb, (uint8_t *)h->mb, 384 * bit_depth);
+            init_get_bits(&gb, (uint8_t *)h->mb,
+                          ff_h264_mb_sizes[h->sps.chroma_format_idc] * bit_depth);
 
             for (i = 0; i < 16; i++) {
                 uint16_t *tmp_y = (uint16_t *)(dest_y + i * linesize);
@@ -2157,7 +2160,7 @@ static av_always_inline void hl_decode_mb_internal(H264Context *h, int simple,
             }
         } else {
             for (i = 0; i < 16; i++)
-                memcpy(dest_y + i * linesize, h->mb + i * 8, 16);
+                memcpy(dest_y + i * linesize, (uint8_t *)h->mb + i * 16, 16);
             if (simple || !CONFIG_GRAY || !(s->flags & CODEC_FLAG_GRAY)) {
                 if (!h->sps.chroma_format_idc) {
                     for (i = 0; i < 8; i++) {
@@ -2165,9 +2168,11 @@ static av_always_inline void hl_decode_mb_internal(H264Context *h, int simple,
                         memset(dest_cr + i*uvlinesize, 1 << (bit_depth - 1), 8);
                     }
                 } else {
+                    uint8_t *src_cb = (uint8_t *)h->mb + 256;
+                    uint8_t *src_cr = (uint8_t *)h->mb + 256 + block_h * 8;
                     for (i = 0; i < block_h; i++) {
-                        memcpy(dest_cb + i * uvlinesize, h->mb + 128 + i * 4, 8);
-                        memcpy(dest_cr + i * uvlinesize, h->mb + 160 + i * 4, 8);
+                        memcpy(dest_cb + i * uvlinesize, src_cb + i * 8, 8);
+                        memcpy(dest_cr + i * uvlinesize, src_cr + i * 8, 8);
                     }
                 }
             }
@@ -2358,7 +2363,8 @@ static av_always_inline void hl_decode_mb_444_internal(H264Context *h,
         } else {
             for (p = 0; p < plane_count; p++)
                 for (i = 0; i < 16; i++)
-                    memcpy(dest[p] + i * linesize, h->mb + p * 128 + i * 8, 16);
+                    memcpy(dest[p] + i * linesize,
+                           (uint8_t *)h->mb + p * 256 + i * 16, 16);
         }
     } else {
         if (IS_INTRA(mb_type)) {
index 153d83c6957346f795c8d63d6757875631221126..f5542bfb1d5504260842a45bd051484b567acbd4 100644 (file)
@@ -602,6 +602,7 @@ typedef struct H264Context{
 
 
 extern const uint8_t ff_h264_chroma_qp[5][QP_MAX_NUM+1]; ///< One chroma qp table for each possible bit depth (8-12).
+extern const uint16_t ff_h264_mb_sizes[4];
 
 /**
  * Decode SEI
index 2c83348a5f0656d9d40387c71d097a19ab55eef1..65f2cb4dc8c7a1f44429ff0dce7441332d0b22c3 100644 (file)
@@ -1984,8 +1984,8 @@ decode_intra_mb:
     h->slice_table[ mb_xy ]= h->slice_num;
 
     if(IS_INTRA_PCM(mb_type)) {
-        static const uint16_t mb_sizes[4] = {256,384,512,768};
-        const int mb_size = mb_sizes[h->sps.chroma_format_idc]*h->sps.bit_depth_luma >> 3;
+        const int mb_size = ff_h264_mb_sizes[h->sps.chroma_format_idc] *
+                            h->sps.bit_depth_luma >> 3;
         const uint8_t *ptr;
 
         // We assume these blocks are very rare so we do not optimize it.
index baddd368008682502ce97c0b3ffa5398ccaea87a..a4debade2e01cabc197171613a3379641179a2ab 100644 (file)
@@ -765,8 +765,8 @@ decode_intra_mb:
 
     if(IS_INTRA_PCM(mb_type)){
         unsigned int x;
-        static const uint16_t mb_sizes[4] = {256,384,512,768};
-        const int mb_size = mb_sizes[h->sps.chroma_format_idc]*h->sps.bit_depth_luma >> 3;
+        const int mb_size = ff_h264_mb_sizes[h->sps.chroma_format_idc] *
+                            h->sps.bit_depth_luma >> 3;
 
         // We assume these blocks are very rare so we do not optimize it.
         align_get_bits(&s->gb);
index 3d85bcf132f95ae17b794b9109b0ac455a564ae7..e17a8005a7528f4c2d45ccd371ba89a92edf1afc 100644 (file)
@@ -2655,9 +2655,9 @@ void ff_vp3_idct_put_sse2(uint8_t *dest, int line_size, DCTELEM *block);
 void ff_vp3_idct_add_sse2(uint8_t *dest, int line_size, DCTELEM *block);
 
 int32_t ff_scalarproduct_int16_mmx2(const int16_t *v1, const int16_t *v2,
-                                    int len);
+                                    int order);
 int32_t ff_scalarproduct_int16_sse2(const int16_t *v1, const int16_t *v2,
-                                    int len);
+                                    int order);
 int32_t ff_scalarproduct_and_madd_int16_mmx2(int16_t *v1, const int16_t *v2,
                                              const int16_t *v3,
                                              int order, int mul);
index 87e05c4ddf2973348ed138518db6c18affc8d8b3..42bb479b9b4f3f2e2f0131e3e9e5a4fa5322ef52 100644 (file)
@@ -144,6 +144,8 @@ filter_h6_shuf1: db 0, 5, 1, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11,  7, 12
 filter_h6_shuf2: db 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,  7, 7,  8,  8,  9
 filter_h6_shuf3: db 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,  9, 9, 10, 10, 11
 
+pw_256:  times 8 dw 256
+
 pw_20091: times 4 dw 20091
 pw_17734: times 4 dw 17734
 
@@ -205,8 +207,7 @@ cglobal put_vp8_epel%1_h6, 6, 6 + npicregs, 8, dst, dststride, src, srcstride, h
     pmaddubsw m2, m7
     paddsw    m0, m1
     paddsw    m0, m2
-    paddsw    m0, [pw_64]
-    psraw     m0, 7
+    pmulhrsw  m0, [pw_256]
     packuswb  m0, m0
     movh  [dstq], m0        ; store
 
@@ -219,7 +220,7 @@ cglobal put_vp8_epel%1_h6, 6, 6 + npicregs, 8, dst, dststride, src, srcstride, h
 
 cglobal put_vp8_epel%1_h4, 6, 6 + npicregs, 7, dst, dststride, src, srcstride, height, mx, picreg
     shl      mxd, 4
-    mova      m2, [pw_64]
+    mova      m2, [pw_256]
     mova      m3, [filter_h2_shuf]
     mova      m4, [filter_h4_shuf]
 %ifdef PIC
@@ -235,9 +236,8 @@ cglobal put_vp8_epel%1_h4, 6, 6 + npicregs, 7, dst, dststride, src, srcstride, h
     pshufb    m1, m4
     pmaddubsw m0, m5
     pmaddubsw m1, m6
-    paddsw    m0, m2
     paddsw    m0, m1
-    psraw     m0, 7
+    pmulhrsw  m0, m2
     packuswb  m0, m0
     movh  [dstq], m0        ; store
 
@@ -255,7 +255,7 @@ cglobal put_vp8_epel%1_v4, 7, 7, 8, dst, dststride, src, srcstride, height, picr
 %endif
     mova      m5, [fourtap_filter_hb+myq-16]
     mova      m6, [fourtap_filter_hb+myq]
-    mova      m7, [pw_64]
+    mova      m7, [pw_256]
 
     ; read 3 lines
     sub     srcq, srcstrideq
@@ -275,8 +275,7 @@ cglobal put_vp8_epel%1_v4, 7, 7, 8, dst, dststride, src, srcstride, height, picr
     pmaddubsw m2, m6
     paddsw    m4, m2
     mova      m2, m3
-    paddsw    m4, m7
-    psraw     m4, 7
+    pmulhrsw  m4, m7
     packuswb  m4, m4
     movh  [dstq], m4
 
@@ -319,9 +318,8 @@ cglobal put_vp8_epel%1_v6, 7, 7, 8, dst, dststride, src, srcstride, height, picr
     paddsw    m6, m1
     paddsw    m6, m7
     mova      m1, m2
-    paddsw    m6, [pw_64]
     mova      m2, m3
-    psraw     m6, 7
+    pmulhrsw  m6, [pw_256]
     mova      m3, m4
     packuswb  m6, m6
     mova      m4, m5
index 1fd6cce9c7e8a02048058c9d0a2c404d3513af55..8535d73f3a693b2ea5191e7a37a7a6adaa6e008a 100644 (file)
@@ -104,7 +104,7 @@ static void apply_unsharp(      uint8_t *dst, int dst_stride,
             }
             if (x >= fp->steps_x && y >= fp->steps_y) {
                 const uint8_t *srx = src - fp->steps_y * src_stride + x - fp->steps_x;
-                uint8_t       *dsx = dst - fp->steps_y * dst_stride + x - fp->steps_x;
+                uint8_t *dsx       = dst - fp->steps_y * dst_stride + x - fp->steps_x;
 
                 res = (int32_t)*srx + ((((int32_t) * srx - (int32_t)((tmp1 + fp->halfscale) >> fp->scalebits)) * fp->amount) >> 16);
                 *dsx = av_clip_uint8(res);
index 1d139a67ee3ad93e6e162d3f105e98d4736e694c..a3c00ced613fb2f08709d67164c88c94e533faf4 100644 (file)
@@ -425,7 +425,8 @@ static void palToUV_c(uint16_t *dstU, int16_t *dstV,
 static void monowhite2Y_c(int16_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2,  int width, uint32_t *unused)
 {
     int i, j;
-    for (i=0; i<width/8; i++) {
+    width = (width + 7) >> 3;
+    for (i = 0; i < width; i++) {
         int d= ~src[i];
         for(j=0; j<8; j++)
             dst[8*i+j]= ((d>>(7-j))&1)*16383;
@@ -440,7 +441,8 @@ static void monowhite2Y_c(int16_t *dst, const uint8_t *src, const uint8_t *unuse
 static void monoblack2Y_c(int16_t *dst, const uint8_t *src, const uint8_t *unused1, const uint8_t *unused2,  int width, uint32_t *unused)
 {
     int i, j;
-    for (i=0; i<width/8; i++) {
+    width = (width + 7) >> 3;
+    for (i = 0; i < width; i++) {
         int d= src[i];
         for(j=0; j<8; j++)
             dst[8*i+j]= ((d>>(7-j))&1)*16383;
index 34ed114207cc8fcd170ffc8cff472914c074698d..6b17c922baa06aab8b4bb23e005702bb5d307b7b 100644 (file)
@@ -320,7 +320,7 @@ yuv2mono_X_c_template(SwsContext *c, const int16_t *lumFilter,
     int i;
     unsigned acc = 0;
 
-    for (i = 0; i < dstW - 1; i += 2) {
+    for (i = 0; i < dstW; i += 2) {
         int j;
         int Y1 = 1 << 18;
         int Y2 = 1 << 18;
@@ -341,6 +341,10 @@ yuv2mono_X_c_template(SwsContext *c, const int16_t *lumFilter,
             output_pixel(*dest++, acc);
         }
     }
+
+    if (i & 6) {
+        output_pixel(*dest, acc);
+    }
 }
 
 static av_always_inline void
@@ -355,7 +359,7 @@ yuv2mono_2_c_template(SwsContext *c, const int16_t *buf[2],
     int  yalpha1 = 4095 - yalpha;
     int i;
 
-    for (i = 0; i < dstW - 7; i += 8) {
+    for (i = 0; i < dstW; i += 8) {
         int Y, acc = 0;
 
         Y = (buf0[i + 0] * yalpha1 + buf1[i + 0] * yalpha) >> 19;
@@ -388,7 +392,7 @@ yuv2mono_1_c_template(SwsContext *c, const int16_t *buf0,
     const uint8_t * const d128 = dither_8x8_220[y & 7];
     int i;
 
-    for (i = 0; i < dstW - 7; i += 8) {
+    for (i = 0; i < dstW; i += 8) {
         int acc = 0;
 
         accumulate_bit(acc, ((buf0[i + 0] + 64) >> 7) + d128[0]);
index b5e0568b10cdc06f21489438ad3eda32df688cfa..f2c5ca8474df903fb304249ba6fcda70edefdfb7 100644 (file)
@@ -46,6 +46,7 @@ include $(SRC_PATH)/tests/fate/amrnb.mak
 include $(SRC_PATH)/tests/fate/amrwb.mak
 include $(SRC_PATH)/tests/fate/atrac.mak
 include $(SRC_PATH)/tests/fate/audio.mak
+include $(SRC_PATH)/tests/fate/bmp.mak
 include $(SRC_PATH)/tests/fate/cdxl.mak
 include $(SRC_PATH)/tests/fate/dct.mak
 include $(SRC_PATH)/tests/fate/demux.mak
diff --git a/tests/fate/bmp.mak b/tests/fate/bmp.mak
new file mode 100644 (file)
index 0000000..56b5059
--- /dev/null
@@ -0,0 +1,41 @@
+FATE_BMP += fate-bmp-1bit
+fate-bmp-1bit: CMD = framecrc -i $(SAMPLES)/bmp/test1.bmp -pix_fmt rgb24
+
+FATE_BMP += fate-bmp-4bit
+fate-bmp-4bit: CMD = framecrc -i $(SAMPLES)/bmp/test4.bmp -pix_fmt rgb24
+
+FATE_BMP += fate-bmp-4bit-os2
+fate-bmp-4bit-os2: CMD = framecrc -i $(SAMPLES)/bmp/test4os2v2.bmp -pix_fmt rgb24
+
+FATE_BMP += fate-bmp-8bit
+fate-bmp-8bit: CMD = framecrc -i $(SAMPLES)/bmp/test8.bmp -pix_fmt rgb24
+
+FATE_BMP += fate-bmp-8bit-os2
+fate-bmp-8bit-os2: CMD = framecrc -i $(SAMPLES)/bmp/test8os2.bmp -pix_fmt rgb24
+
+FATE_BMP += fate-bmp-15bit
+fate-bmp-15bit: CMD = framecrc -i $(SAMPLES)/bmp/test16.bmp -pix_fmt rgb555le
+
+FATE_BMP += fate-bmp-15bit-mask
+fate-bmp-15bit-mask: CMD = framecrc -i $(SAMPLES)/bmp/test16bf555.bmp -pix_fmt rgb555le
+
+FATE_BMP += fate-bmp-16bit-mask
+fate-bmp-16bit-mask: CMD = framecrc -i $(SAMPLES)/bmp/test16bf565.bmp -pix_fmt rgb565le
+
+FATE_BMP += fate-bmp-24bit
+fate-bmp-24bit: CMD = framecrc -i $(SAMPLES)/bmp/test24.bmp
+
+FATE_BMP += fate-bmp-32bit
+fate-bmp-32bit: CMD = framecrc -i $(SAMPLES)/bmp/test32.bmp -pix_fmt bgr24
+
+FATE_BMP += fate-bmp-32bit-mask
+fate-bmp-32bit-mask: CMD = framecrc -i $(SAMPLES)/bmp/test32bf.bmp -pix_fmt bgr24
+
+FATE_BMP += fate-bmp-rle4
+fate-bmp-rle4: CMD = framecrc -i $(SAMPLES)/bmp/testcompress4.bmp -pix_fmt rgb24
+
+FATE_BMP += fate-bmp-rle8
+fate-bmp-rle8: CMD = framecrc -i $(SAMPLES)/bmp/testcompress8.bmp -pix_fmt rgb24
+
+FATE_TESTS += $(FATE_BMP)
+fate-bmp: $(FATE_BMP)
diff --git a/tests/ref/fate/bmp-15bit b/tests/ref/fate/bmp-15bit
new file mode 100644 (file)
index 0000000..a0f3bbf
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    16256, 0xdbcf881d
diff --git a/tests/ref/fate/bmp-15bit-mask b/tests/ref/fate/bmp-15bit-mask
new file mode 100644 (file)
index 0000000..a0f3bbf
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    16256, 0xdbcf881d
diff --git a/tests/ref/fate/bmp-16bit-mask b/tests/ref/fate/bmp-16bit-mask
new file mode 100644 (file)
index 0000000..afa5ab4
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    16256, 0x44675948
diff --git a/tests/ref/fate/bmp-1bit b/tests/ref/fate/bmp-1bit
new file mode 100644 (file)
index 0000000..1c825b1
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    24384, 0x4c968301
diff --git a/tests/ref/fate/bmp-24bit b/tests/ref/fate/bmp-24bit
new file mode 100644 (file)
index 0000000..8f1a615
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    24384, 0x325dd8d9
diff --git a/tests/ref/fate/bmp-32bit b/tests/ref/fate/bmp-32bit
new file mode 100644 (file)
index 0000000..8f1a615
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    24384, 0x325dd8d9
diff --git a/tests/ref/fate/bmp-32bit-mask b/tests/ref/fate/bmp-32bit-mask
new file mode 100644 (file)
index 0000000..8f1a615
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    24384, 0x325dd8d9
diff --git a/tests/ref/fate/bmp-4bit b/tests/ref/fate/bmp-4bit
new file mode 100644 (file)
index 0000000..c0eedf1
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    24384, 0x322d81f4
diff --git a/tests/ref/fate/bmp-4bit-os2 b/tests/ref/fate/bmp-4bit-os2
new file mode 100644 (file)
index 0000000..8a5f658
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    19800, 0x563b599a
diff --git a/tests/ref/fate/bmp-8bit b/tests/ref/fate/bmp-8bit
new file mode 100644 (file)
index 0000000..887113c
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    24384, 0xa7aa6b9b
diff --git a/tests/ref/fate/bmp-8bit-os2 b/tests/ref/fate/bmp-8bit-os2
new file mode 100644 (file)
index 0000000..887113c
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    24384, 0xa7aa6b9b
diff --git a/tests/ref/fate/bmp-rle4 b/tests/ref/fate/bmp-rle4
new file mode 100644 (file)
index 0000000..c0eedf1
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    24384, 0x322d81f4
diff --git a/tests/ref/fate/bmp-rle8 b/tests/ref/fate/bmp-rle8
new file mode 100644 (file)
index 0000000..887113c
--- /dev/null
@@ -0,0 +1,2 @@
+#tb 0: 1/25
+0,          0,          0,        1,    24384, 0xa7aa6b9b