Merge commit '124134e42455763b28cc346fed1d07017a76e84e'
[ffmpeg.git] / libavdevice / dshow.c
index 2a7cdd1..48bab37 100644 (file)
@@ -36,6 +36,7 @@ struct dshow_ctx {
 
     int   list_options;
     int   list_devices;
+    int   audio_buffer_size;
 
     IBaseFilter *device_filter[2];
     IPin        *device_pin[2];
@@ -46,7 +47,7 @@ struct dshow_ctx {
     HANDLE event;
     AVPacketList *pktl;
 
-    unsigned int curbufsize;
+    int64_t curbufsize;
     unsigned int video_frame_num;
 
     IMediaControl *control;
@@ -92,16 +93,16 @@ static enum PixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
     return PIX_FMT_NONE;
 }
 
-static enum CodecID dshow_codecid(DWORD biCompression)
+static enum AVCodecID dshow_codecid(DWORD biCompression)
 {
     switch(biCompression) {
     case MKTAG('d', 'v', 's', 'd'):
-        return CODEC_ID_DVVIDEO;
+        return AV_CODEC_ID_DVVIDEO;
     case MKTAG('M', 'J', 'P', 'G'):
     case MKTAG('m', 'j', 'p', 'g'):
-        return CODEC_ID_MJPEG;
+        return AV_CODEC_ID_MJPEG;
     }
-    return CODEC_ID_NONE;
+    return AV_CODEC_ID_NONE;
 }
 
 static int
@@ -207,11 +208,11 @@ callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time)
 
 //    dump_videohdr(s, vdhdr);
 
-    if(shall_we_drop(s))
-        return;
-
     WaitForSingleObject(ctx->mutex, INFINITE);
 
+    if(shall_we_drop(s))
+        goto fail;
+
     pktl_next = av_mallocz(sizeof(AVPacketList));
     if(!pktl_next)
         goto fail;
@@ -447,6 +448,51 @@ end:
 }
 
 /**
+ * Set audio device buffer size in milliseconds (which can directly impact
+ * latency, depending on the device).
+ */
+static int
+dshow_set_audio_buffer_size(AVFormatContext *avctx, IPin *pin)
+{
+    struct dshow_ctx *ctx = avctx->priv_data;
+    IAMBufferNegotiation *buffer_negotiation = NULL;
+    ALLOCATOR_PROPERTIES props = { -1, -1, -1, -1 };
+    IAMStreamConfig *config = NULL;
+    AM_MEDIA_TYPE *type = NULL;
+    int ret = AVERROR(EIO);
+
+    if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
+        goto end;
+    if (IAMStreamConfig_GetFormat(config, &type) != S_OK)
+        goto end;
+    if (!IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx))
+        goto end;
+
+    props.cbBuffer = (((WAVEFORMATEX *) type->pbFormat)->nAvgBytesPerSec)
+                   * ctx->audio_buffer_size / 1000;
+
+    if (IPin_QueryInterface(pin, &IID_IAMBufferNegotiation, (void **) &buffer_negotiation) != S_OK)
+        goto end;
+    if (IAMBufferNegotiation_SuggestAllocatorProperties(buffer_negotiation, &props) != S_OK)
+        goto end;
+
+    ret = 0;
+
+end:
+    if (buffer_negotiation)
+        IAMBufferNegotiation_Release(buffer_negotiation);
+    if (type) {
+        if (type->pbFormat)
+            CoTaskMemFree(type->pbFormat);
+        CoTaskMemFree(type);
+    }
+    if (config)
+        IAMStreamConfig_Release(config);
+
+    return ret;
+}
+
+/**
  * Cycle through available pins using the device_filter device, of type
  * devtype, retrieve the first output pin and return the pointer to the
  * object found in *ppin.
@@ -513,6 +559,10 @@ dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
                 goto next;
             }
         }
+        if (devtype == AudioDevice && ctx->audio_buffer_size) {
+            if (dshow_set_audio_buffer_size(avctx, pin) < 0)
+                goto next;
+        }
 
         if (IPin_EnumMediaTypes(pin, &types) != S_OK)
             goto next;
@@ -639,13 +689,13 @@ error:
     return ret;
 }
 
-static enum CodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
+static enum AVCodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
 {
     switch (sample_fmt) {
-    case AV_SAMPLE_FMT_U8:  return CODEC_ID_PCM_U8;
-    case AV_SAMPLE_FMT_S16: return CODEC_ID_PCM_S16LE;
-    case AV_SAMPLE_FMT_S32: return CODEC_ID_PCM_S32LE;
-    default:                return CODEC_ID_NONE; /* Should never happen. */
+    case AV_SAMPLE_FMT_U8:  return AV_CODEC_ID_PCM_U8;
+    case AV_SAMPLE_FMT_S16: return AV_CODEC_ID_PCM_S16LE;
+    case AV_SAMPLE_FMT_S32: return AV_CODEC_ID_PCM_S32LE;
+    default:                return AV_CODEC_ID_NONE; /* Should never happen. */
     }
 }
 
@@ -706,7 +756,7 @@ dshow_add_device(AVFormatContext *avctx,
         codec->pix_fmt    = dshow_pixfmt(bih->biCompression, bih->biBitCount);
         if (codec->pix_fmt == PIX_FMT_NONE) {
             codec->codec_id = dshow_codecid(bih->biCompression);
-            if (codec->codec_id == CODEC_ID_NONE) {
+            if (codec->codec_id == AV_CODEC_ID_NONE) {
                 av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
                                  "Please report verbose (-v 9) debug information.\n");
                 dshow_read_close(avctx);
@@ -714,7 +764,7 @@ dshow_add_device(AVFormatContext *avctx,
             }
             codec->bits_per_coded_sample = bih->biBitCount;
         } else {
-            codec->codec_id = CODEC_ID_RAWVIDEO;
+            codec->codec_id = AV_CODEC_ID_RAWVIDEO;
             if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) {
                 codec->bits_per_coded_sample = bih->biBitCount;
                 codec->extradata = av_malloc(9 + FF_INPUT_BUFFER_PADDING_SIZE);
@@ -916,10 +966,11 @@ static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
     while (!pktl) {
         WaitForSingleObject(ctx->mutex, INFINITE);
         pktl = ctx->pktl;
-        if (ctx->pktl) {
-            *pkt = ctx->pktl->pkt;
+        if (pktl) {
+            *pkt = pktl->pkt;
             ctx->pktl = ctx->pktl->next;
             av_free(pktl);
+            ctx->curbufsize -= pkt->size;
         }
         ResetEvent(ctx->event);
         ReleaseMutex(ctx->mutex);
@@ -932,8 +983,6 @@ static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
         }
     }
 
-    ctx->curbufsize -= pkt->size;
-
     return pkt->size;
 }
 
@@ -946,13 +995,14 @@ static const AVOption options[] = {
     { "sample_size", "set audio sample size", OFFSET(sample_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, 16, DEC },
     { "channels", "set number of audio channels, such as 1 or 2", OFFSET(channels), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, DEC },
     { "list_devices", "list available devices", OFFSET(list_devices), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1, DEC, "list_devices" },
-    { "true", "", 0, AV_OPT_TYPE_CONST, {.dbl=1}, 0, 0, DEC, "list_devices" },
-    { "false", "", 0, AV_OPT_TYPE_CONST, {.dbl=0}, 0, 0, DEC, "list_devices" },
+    { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "list_devices" },
+    { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "list_devices" },
     { "list_options", "list available options for specified device", OFFSET(list_options), AV_OPT_TYPE_INT, {.dbl=0}, 0, 1, DEC, "list_options" },
-    { "true", "", 0, AV_OPT_TYPE_CONST, {.dbl=1}, 0, 0, DEC, "list_options" },
-    { "false", "", 0, AV_OPT_TYPE_CONST, {.dbl=0}, 0, 0, DEC, "list_options" },
+    { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, DEC, "list_options" },
+    { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, DEC, "list_options" },
     { "video_device_number", "set video device number for devices with same name (starts at 0)", OFFSET(video_device_number), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, DEC },
     { "audio_device_number", "set audio device number for devices with same name (starts at 0)", OFFSET(audio_device_number), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, DEC },
+    { "audio_buffer_size", "set audio device buffer latency size in milliseconds (default is the device's default)", OFFSET(audio_buffer_size), AV_OPT_TYPE_INT, {.dbl = 0}, 0, INT_MAX, DEC },
     { NULL },
 };