[FFmpeg-devel] [GSoC] BDA (DTV) Capture / tuning -- work-in-progress

Roger Pack rogerdpack2 at gmail.com
Wed Dec 30 00:23:48 CET 2015


> OK I had this great idea to capture the incoming MPEG2 transport
> stream from the digital TV capture device.  Kind of like "raw" stream,
> so FFmpeg could have access to, for instance, all the audio stream.
>
> It appears that the type coming out of the tuner is:
> MEDIATYPE_Stream
> with subtype
> KSDATAFORMAT_SUBTYPE_BDA_MPEG2_TRANSPORT
> which is apparently treated the same as MEDIASUBTYPE_MPEG2_TRANSPORT
> by the built in directshow mpeg demuxer [1] so I assume is some kind
> of typical MPEG2 TS stream.
>
> I had hoped that if I set dshow's AVStream's codec_id to
>          codec->codec_id = AV_CODEC_ID_NONE;
>          codec->codec_type = AVMEDIA_TYPE_DATA;

Oops that was meant to be

            codec->codec_id = AV_CODEC_ID_MPEG2TS;
            codec->codec_type = AVMEDIA_TYPE_DATA;

> That it would somehow recognize that I was sending it an MPEG stream
> and insert an appropriate demuxer for me.
>
> However, when I run it, it fails like this:
>
> Input #0, dshow, from 'video=Hauppauge WinTV 885 BDA Tuner/Demod':
>   Duration: N/A, bitrate: N/A
> Codec 0x20000 is not in the full list.
>     Stream #0:0, 0, 1/27000000: Data: unknown_codec, 0/1
> Successfully opened the file.
> Output #0, mp4, to 'yo.mp4':
> Output file #0 does not contain any stream
>
> so it's definitely not, for instance, doing a probe or analyze on the
> MPEG stream....
>
> Is this possible or any hints/tips/tricks I could possibly use?

To answer my own question, I turned the dshow capture device into both
an AVInputFormat *and* a URLProtocol that "wraps" the AVInputFormat.
Apparently ffmpeg can receive "raw" bytes only from URLProtocol (?)
This way worked great both "segmented" MPEG2VIDEO streams as well as
"raw" MPEG TS streams.

Still a bit unexpected to be necessary, but in case its interesting to
followers, here was the wrapper code (will hopefully be committed to
git trunk soon'ish once I clean it up).

Thanks all.
-roger-

static int dshow_url_open(URLContext *h, const char *filename, int flags)
{
    struct dshow_ctx *ctx = h->priv_data;
    if (!(ctx->protocol_av_format_context = avformat_alloc_context()))
     return AVERROR(ENOMEM);
    ctx->protocol_av_format_context->flags = h->flags;

    av_strstart(filename, "dshowbda:", &filename); // remove prefix "dshowbda:"
    if (filename)
      av_strlcpy(ctx->protocol_av_format_context->filename, filename,
1024); // 1024 max bytes
    ctx->protocol_av_format_context->iformat = &ff_dshow_demuxer;
    ctx->protocol_latest_packet = av_packet_alloc();
    ctx->protocol_latest_packet->pos = 0; // default is -1
    if (!ctx->protocol_latest_packet)
      return AVERROR(ENOMEM);
    ctx->protocol_av_format_context->priv_data = ctx; // a bit
circular, but needed to pass through the settings
    return dshow_read_header(ctx->protocol_av_format_context);
}

static int dshow_url_read(URLContext *h, uint8_t *buf, int max_size)
{
    struct dshow_ctx *ctx = h->priv_data;
    int packet_size_or_fail;
    int bytes_to_copy;
    int bytes_left = ctx->protocol_latest_packet->size -
ctx->protocol_latest_packet->pos;

    if (bytes_left == 0) {
      av_packet_unref(ctx->protocol_latest_packet);
      packet_size_or_fail =
dshow_read_packet(ctx->protocol_av_format_context,
ctx->protocol_latest_packet);
      if (packet_size_or_fail < 0)
        return packet_size_or_fail;
      av_assert0(ctx->protocol_latest_packet->stream_index == 0); //
this should be a stream based, so only one stream, so always index 0
      av_assert0(packet_size_or_fail ==
ctx->protocol_latest_packet->size); // should match...
      ctx->protocol_latest_packet->pos = 0; // default is -1
      bytes_left = ctx->protocol_latest_packet->size -
ctx->protocol_latest_packet->pos;
      av_log(h, AV_LOG_VERBOSE, "dshow_url_read read packet of size
%d\n", ctx->protocol_latest_packet->size);
    }
    bytes_to_copy = FFMIN(bytes_left, max_size);
    if (bytes_to_copy != bytes_left)
        av_log(h, AV_LOG_DEBUG, "passing partial dshow packet %d >
%d\n", bytes_left, max_size);
    memcpy(buf,
&ctx->protocol_latest_packet->data[ctx->protocol_latest_packet->pos],
bytes_to_copy);
    ctx->protocol_latest_packet->pos += bytes_to_copy;
    av_log(h, AV_LOG_VERBOSE, "dshow_url_read returning %d\n", bytes_to_copy);
    return bytes_to_copy;;
}

static int dshow_url_close(URLContext *h)
{
    struct dshow_ctx *ctx = h->priv_data;
    int ret = dshow_read_close(ctx->protocol_av_format_context);
    ctx->protocol_av_format_context->priv_data = NULL; // just in case
it would be freed below
    avformat_free_context(ctx->protocol_av_format_context);
    av_packet_free(&ctx->protocol_latest_packet); // free wrapper,
also does an unref
    return ret;
}

Thanks!
-roger-


More information about the ffmpeg-devel mailing list