Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Soft Works <softworkz@hotmail.com>
To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Subject: Re: [FFmpeg-devel] [PATCH v4 6/6] avcodec/qsvdec: Implement SEI parsing for QSV decoders
Date: Tue, 28 Jun 2022 05:25:49 +0000
Message-ID: <DM8P223MB03655121F25A223E7F3F118CBAB89@DM8P223MB0365.NAMP223.PROD.OUTLOOK.COM> (raw)
In-Reply-To: <DB6PR0101MB2214845C63CD8F8FFB6944038FB89@DB6PR0101MB2214.eurprd01.prod.exchangelabs.com>



> -----Original Message-----
> From: ffmpeg-devel <ffmpeg-devel-bounces@ffmpeg.org> On Behalf Of
> Andreas Rheinhardt
> Sent: Tuesday, June 28, 2022 6:17 AM
> To: ffmpeg-devel@ffmpeg.org
> Subject: Re: [FFmpeg-devel] [PATCH v4 6/6] avcodec/qsvdec: Implement
> SEI parsing for QSV decoders
> 
> softworkz:
> > From: softworkz <softworkz@hotmail.com>
> >
> > Signed-off-by: softworkz <softworkz@hotmail.com>
> > ---
> >  libavcodec/qsvdec.c | 234
> ++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 234 insertions(+)
> >
> > diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
> > index 5fc5bed4c8..e854f363ec 100644
> > --- a/libavcodec/qsvdec.c
> > +++ b/libavcodec/qsvdec.c
> > @@ -49,6 +49,12 @@
> >  #include "hwconfig.h"
> >  #include "qsv.h"
> >  #include "qsv_internal.h"
> > +#include "h264dec.h"
> > +#include "h264_sei.h"
> > +#include "hevcdec.h"
> > +#include "hevc_ps.h"
> > +#include "hevc_sei.h"
> > +#include "mpeg12.h"
> >
> >  static const AVRational mfx_tb = { 1, 90000 };
> >
> > @@ -60,6 +66,8 @@ static const AVRational mfx_tb = { 1, 90000 };
> >      AV_NOPTS_VALUE : pts_tb.num ? \
> >      av_rescale_q(mfx_pts, mfx_tb, pts_tb) : mfx_pts)
> >
> > +#define PAYLOAD_BUFFER_SIZE 65535
> > +
> >  typedef struct QSVAsyncFrame {
> >      mfxSyncPoint *sync;
> >      QSVFrame     *frame;
> > @@ -101,6 +109,9 @@ typedef struct QSVContext {
> >
> >      mfxExtBuffer **ext_buffers;
> >      int         nb_ext_buffers;
> > +
> > +    mfxU8 payload_buffer[PAYLOAD_BUFFER_SIZE];
> > +    Mpeg1Context mpeg_ctx;
> >  } QSVContext;
> >
> >  static const AVCodecHWConfigInternal *const qsv_hw_configs[] = {
> > @@ -599,6 +610,210 @@ static int
> qsv_export_film_grain(AVCodecContext *avctx, mfxExtAV1FilmGrainParam
> >      return 0;
> >  }
> >  #endif
> > +static int find_start_offset(mfxU8 data[4])
> > +{
> > +    if (data[0] == 0 && data[1] == 0 && data[2] == 1)
> > +        return 3;
> > +
> > +    if (data[0] == 0 && data[1] == 0 && data[2] == 0 && data[3] ==
> 1)
> > +        return 4;
> > +
> > +    return 0;
> > +}
> > +
> > +static int parse_sei_h264(AVCodecContext* avctx, QSVContext* q,
> AVFrame* out)
> > +{
> > +    H264SEIContext sei = { 0 };
> > +    GetBitContext gb = { 0 };
> > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> .BufSize = sizeof(q->payload_buffer) };
> > +    mfxU64 ts;
> > +    int ret;
> > +
> > +    while (1) {
> > +        int start;
> > +        memset(payload.Data, 0, payload.BufSize);
> > +
> > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> &payload);
> > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> >payload_buffer), payload.BufSize);
> > +            return 0;
> > +        }
> > +        if (ret != MFX_ERR_NONE)
> > +            return ret;
> > +
> > +        if (payload.NumBit == 0 || payload.NumBit >=
> payload.BufSize * 8)
> > +            break;
> > +
> > +        start = find_start_offset(payload.Data);
> > +
> > +        switch (payload.Type) {
> > +            case SEI_TYPE_BUFFERING_PERIOD:
> > +            case SEI_TYPE_PIC_TIMING:
> > +                continue;
> > +        }
> > +
> > +        if (init_get_bits(&gb, &payload.Data[start],
> payload.NumBit - start * 8) < 0)
> > +            av_log(avctx, AV_LOG_ERROR, "Error initializing
> bitstream reader SEI type: %d  Numbits %d error: %d\n", payload.Type,
> payload.NumBit, ret);
> > +        else {
> > +            ret = ff_h264_sei_decode(&sei, &gb, NULL, avctx);
> > +
> > +            if (ret < 0)
> > +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI
> type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit,
> ret);
> > +            else
> > +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d
> Numbits %d\n", payload.Type, payload.NumBit);
> > +        }
> > +    }
> > +
> > +    if (out)
> > +        return ff_h264_export_frame_props(avctx, &sei, NULL, out);
> > +
> > +    return 0;
> > +}
> > +
> > +static int parse_sei_hevc(AVCodecContext* avctx, QSVContext* q,
> QSVFrame* out)
> > +{
> > +    HEVCSEI sei = { 0 };
> > +    HEVCParamSets ps = { 0 };
> > +    GetBitContext gb = { 0 };
> > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> .BufSize = sizeof(q->payload_buffer) };
> > +    mfxFrameSurface1 *surface = &out->surface;
> > +    mfxU64 ts;
> > +    int ret, has_logged = 0;
> > +
> > +    while (1) {
> > +        int start;
> > +        memset(payload.Data, 0, payload.BufSize);
> > +
> > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> &payload);
> > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> >payload_buffer), payload.BufSize);
> > +            return 0;
> > +        }
> > +        if (ret != MFX_ERR_NONE)
> > +            return ret;
> > +
> > +        if (payload.NumBit == 0 || payload.NumBit >=
> payload.BufSize * 8)
> > +            break;
> > +
> > +        if (!has_logged) {
> > +            has_logged = 1;
> > +            av_log(avctx, AV_LOG_VERBOSE, "-----------------------
> ------------------\n");
> > +            av_log(avctx, AV_LOG_VERBOSE, "Start reading SEI -
> payload timestamp: %llu - surface timestamp: %llu\n", ts, surface-
> >Data.TimeStamp);
> > +        }
> > +
> > +        if (ts != surface->Data.TimeStamp) {
> > +            av_log(avctx, AV_LOG_WARNING, "GetPayload timestamp
> (%llu) does not match surface timestamp: (%llu)\n", ts, surface-
> >Data.TimeStamp);
> > +        }
> > +
> > +        start = find_start_offset(payload.Data);
> > +
> > +        av_log(avctx, AV_LOG_VERBOSE, "parsing SEI type: %3d
> Numbits %3d  Start: %d\n", payload.Type, payload.NumBit, start);
> > +
> > +        switch (payload.Type) {
> > +            case SEI_TYPE_BUFFERING_PERIOD:
> > +            case SEI_TYPE_PIC_TIMING:
> > +                continue;
> > +            case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
> > +                // There seems to be a bug in MSDK
> > +                payload.NumBit -= 8;
> > +
> > +                break;
> > +            case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
> > +                // There seems to be a bug in MSDK
> > +                payload.NumBit = 48;
> > +
> > +                break;
> > +            case SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35:
> > +                // There seems to be a bug in MSDK
> > +                if (payload.NumBit == 552)
> > +                    payload.NumBit = 528;
> > +                break;
> > +        }
> > +
> > +        if (init_get_bits(&gb, &payload.Data[start],
> payload.NumBit - start * 8) < 0)
> > +            av_log(avctx, AV_LOG_ERROR, "Error initializing
> bitstream reader SEI type: %d  Numbits %d error: %d\n", payload.Type,
> payload.NumBit, ret);
> > +        else {
> > +            ret = ff_hevc_decode_nal_sei(&gb, avctx, &sei, &ps,
> HEVC_NAL_SEI_PREFIX);
> > +
> > +            if (ret < 0)
> > +                av_log(avctx, AV_LOG_WARNING, "Failed to parse SEI
> type: %d  Numbits %d error: %d\n", payload.Type, payload.NumBit,
> ret);
> > +            else
> > +                av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d
> Numbits %d\n", payload.Type, payload.NumBit);
> > +        }
> > +    }
> > +
> > +    if (has_logged) {
> > +        av_log(avctx, AV_LOG_VERBOSE, "End reading SEI\n");
> > +    }
> > +
> > +    if (out && out->frame)
> > +        return ff_hevc_set_side_data(avctx, &sei, NULL, out-
> >frame);
> > +
> > +    return 0;
> > +}
> > +
> > +static int parse_sei_mpeg12(AVCodecContext* avctx, QSVContext* q,
> AVFrame* out)
> > +{
> > +    Mpeg1Context *mpeg_ctx = &q->mpeg_ctx;
> > +    mfxPayload payload = { 0, .Data = &q->payload_buffer[0],
> .BufSize = sizeof(q->payload_buffer) };
> > +    mfxU64 ts;
> > +    int ret;
> > +
> > +    while (1) {
> > +        int start;
> > +
> > +        memset(payload.Data, 0, payload.BufSize);
> > +        ret = MFXVideoDECODE_GetPayload(q->session, &ts,
> &payload);
> > +        if (ret == MFX_ERR_NOT_ENOUGH_BUFFER) {
> > +            av_log(avctx, AV_LOG_WARNING, "Warning: Insufficient
> buffer on GetPayload(). Size: %"PRIu64" Needed: %d\n", sizeof(q-
> >payload_buffer), payload.BufSize);
> > +            return 0;
> > +        }
> > +        if (ret != MFX_ERR_NONE)
> > +            return ret;
> > +
> > +        if (payload.NumBit == 0 || payload.NumBit >=
> payload.BufSize * 8)
> > +            break;
> > +
> > +        start = find_start_offset(payload.Data);
> > +
> > +        start++;
> > +
> > +        ff_mpeg_decode_user_data(avctx, mpeg_ctx,
> &payload.Data[start], (int)((payload.NumBit + 7) / 8) - start);
> > +
> > +        av_log(avctx, AV_LOG_DEBUG, "mfxPayload Type: %d  Numbits
> %d start %d -> %.s\n", payload.Type, payload.NumBit, start, (char
> *)(&payload.Data[start]));
> > +    }
> > +
> > +    if (!out)
> > +        return 0;
> > +
> > +    if (mpeg_ctx->a53_buf_ref) {
> > +
> > +        AVFrameSideData *sd = av_frame_new_side_data_from_buf(out,
> AV_FRAME_DATA_A53_CC, mpeg_ctx->a53_buf_ref);
> > +        if (!sd)
> > +            av_buffer_unref(&mpeg_ctx->a53_buf_ref);
> > +        mpeg_ctx->a53_buf_ref = NULL;
> > +    }
> > +
> > +    if (mpeg_ctx->has_stereo3d) {
> > +        AVStereo3D *stereo = av_stereo3d_create_side_data(out);
> > +        if (!stereo)
> > +            return AVERROR(ENOMEM);
> > +
> > +        *stereo = mpeg_ctx->stereo3d;
> > +        mpeg_ctx->has_stereo3d = 0;
> > +    }
> > +
> > +    if (mpeg_ctx->has_afd) {
> > +        AVFrameSideData *sd = av_frame_new_side_data(out,
> AV_FRAME_DATA_AFD, 1);
> > +        if (!sd)
> > +            return AVERROR(ENOMEM);
> > +
> > +        *sd->data   = mpeg_ctx->afd;
> > +        mpeg_ctx->has_afd = 0;
> > +    }
> > +
> > +    return 0;
> > +}
> >
> >  static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
> >                        AVFrame *frame, int *got_frame,
> > @@ -636,6 +851,8 @@ static int qsv_decode(AVCodecContext *avctx,
> QSVContext *q,
> >                                                insurf, &outsurf,
> sync);
> >          if (ret == MFX_WRN_DEVICE_BUSY)
> >              av_usleep(500);
> > +        else if (avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO)
> > +            parse_sei_mpeg12(avctx, q, NULL);
> >
> >      } while (ret == MFX_WRN_DEVICE_BUSY || ret ==
> MFX_ERR_MORE_SURFACE);
> >
> > @@ -677,6 +894,23 @@ static int qsv_decode(AVCodecContext *avctx,
> QSVContext *q,
> >              return AVERROR_BUG;
> >          }
> >
> > +        switch (avctx->codec_id) {
> > +        case AV_CODEC_ID_MPEG2VIDEO:
> > +            ret = parse_sei_mpeg12(avctx, q, out_frame->frame);
> > +            break;
> > +        case AV_CODEC_ID_H264:
> > +            ret = parse_sei_h264(avctx, q, out_frame->frame);
> > +            break;
> > +        case AV_CODEC_ID_HEVC:
> > +            ret = parse_sei_hevc(avctx, q, out_frame);
> > +            break;
> > +        default:
> > +            ret = 0;
> > +        }
> > +
> > +        if (ret < 0)
> > +            av_log(avctx, AV_LOG_ERROR, "Error parsing SEI data:
> %d\n", ret);
> > +
> >          out_frame->queued += 1;
> >
> >          aframe = (QSVAsyncFrame){ sync, out_frame };
> 
> You completely forgot necessary changes to configure/the Makefile.
> The
> way you are doing it here means that you basically have the qsv
> decoders
> to rely on the H.264/HEVC/MPEG-1/2 decoders which is way too much.

You are referring to the hypothetical case where one would disable
one of the sw decoders while having a qsv decoder enabled, right?

The SEI parsing code is not trivial and tied to those decoders 
(means using these contexts). It would be not a straightforward
task to extract/separate those parts, that's why I preferred to
just make that functionality accessible.
I wouldn't mind when the QSV decoders would be dependent on those
decoders being included in compilation, even more when considering
that so many other hwaccel decoders have the same dependencies;
DXVA2, D3D11VA, NVDEC, VAAPI.

The question would be whether to not build the qsv decoders when
the sw decoders are deselected or whether to build the sw decoder
code even these are disabled. AFAIU, both would be possible?

Or would you have a better idea?

Thanks,
sw







_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  reply	other threads:[~2022-06-28  5:26 UTC|newest]

Thread overview: 65+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-26  8:08 [FFmpeg-devel] [PATCH 0/6] " ffmpegagent
2022-05-26  8:08 ` [FFmpeg-devel] [PATCH 1/6] avutil/frame: Add av_frame_copy_side_data() and av_frame_remove_all_side_data() softworkz
2022-05-27 14:35   ` Soft Works
2022-05-26  8:08 ` [FFmpeg-devel] [PATCH 2/6] avcodec/vpp_qsv: Copy side data from input to output frame softworkz
2022-05-31  9:19   ` Xiang, Haihao
2022-05-26  8:08 ` [FFmpeg-devel] [PATCH 3/6] avcodec/mpeg12dec: make mpeg_decode_user_data() accessible softworkz
2022-05-31  9:24   ` Xiang, Haihao
2022-05-26  8:08 ` [FFmpeg-devel] [PATCH 4/6] avcodec/hevcdec: make set_side_data() accessible softworkz
2022-05-31  9:38   ` Xiang, Haihao
2022-05-31 16:03     ` Soft Works
2022-05-31  9:40   ` Xiang, Haihao
2022-05-26  8:08 ` [FFmpeg-devel] [PATCH 5/6] avcodec/h264dec: make h264_export_frame_props() accessible softworkz
2022-05-26  8:08 ` [FFmpeg-devel] [PATCH 6/6] avcodec/qsvdec: Implement SEI parsing for QSV decoders softworkz
2022-06-01  5:15   ` Xiang, Haihao
2022-06-01  8:51     ` Soft Works
2022-06-01  9:06 ` [FFmpeg-devel] [PATCH v2 0/6] " ffmpegagent
2022-06-01  9:06   ` [FFmpeg-devel] [PATCH v2 1/6] avutil/frame: Add av_frame_copy_side_data() and av_frame_remove_all_side_data() softworkz
2022-06-01  9:06   ` [FFmpeg-devel] [PATCH v2 2/6] avcodec/vpp_qsv: Copy side data from input to output frame softworkz
2022-06-01  9:06   ` [FFmpeg-devel] [PATCH v2 3/6] avcodec/mpeg12dec: make mpeg_decode_user_data() accessible softworkz
2022-06-01  9:06   ` [FFmpeg-devel] [PATCH v2 4/6] avcodec/hevcdec: make set_side_data() accessible softworkz
2022-06-01  9:06   ` [FFmpeg-devel] [PATCH v2 5/6] avcodec/h264dec: make h264_export_frame_props() accessible softworkz
2022-06-01  9:06   ` [FFmpeg-devel] [PATCH v2 6/6] avcodec/qsvdec: Implement SEI parsing for QSV decoders softworkz
2022-06-01 17:20     ` Xiang, Haihao
2022-06-01 17:50       ` Soft Works
2022-06-01 18:01   ` [FFmpeg-devel] [PATCH v3 0/6] " ffmpegagent
2022-06-01 18:01     ` [FFmpeg-devel] [PATCH v3 1/6] avutil/frame: Add av_frame_copy_side_data() and av_frame_remove_all_side_data() softworkz
2022-06-24  7:01       ` Xiang, Haihao
2022-06-26 23:35         ` Soft Works
2022-06-01 18:01     ` [FFmpeg-devel] [PATCH v3 2/6] avcodec/vpp_qsv: Copy side data from input to output frame softworkz
2022-06-01 18:01     ` [FFmpeg-devel] [PATCH v3 3/6] avcodec/mpeg12dec: make mpeg_decode_user_data() accessible softworkz
2022-06-01 18:01     ` [FFmpeg-devel] [PATCH v3 4/6] avcodec/hevcdec: make set_side_data() accessible softworkz
2022-06-01 18:01     ` [FFmpeg-devel] [PATCH v3 5/6] avcodec/h264dec: make h264_export_frame_props() accessible softworkz
2022-06-01 18:01     ` [FFmpeg-devel] [PATCH v3 6/6] avcodec/qsvdec: Implement SEI parsing for QSV decoders softworkz
2022-06-26 23:41     ` [FFmpeg-devel] [PATCH v4 0/6] " ffmpegagent
2022-06-26 23:41       ` [FFmpeg-devel] [PATCH v4 1/6] avutil/frame: Add av_frame_copy_side_data() and av_frame_remove_all_side_data() softworkz
2022-06-26 23:41       ` [FFmpeg-devel] [PATCH v4 2/6] avcodec/vpp_qsv: Copy side data from input to output frame softworkz
2022-06-26 23:41       ` [FFmpeg-devel] [PATCH v4 3/6] avcodec/mpeg12dec: make mpeg_decode_user_data() accessible softworkz
2022-06-26 23:41       ` [FFmpeg-devel] [PATCH v4 4/6] avcodec/hevcdec: make set_side_data() accessible softworkz
2022-06-26 23:41       ` [FFmpeg-devel] [PATCH v4 5/6] avcodec/h264dec: make h264_export_frame_props() accessible softworkz
2022-06-26 23:41       ` [FFmpeg-devel] [PATCH v4 6/6] avcodec/qsvdec: Implement SEI parsing for QSV decoders softworkz
2022-06-28  4:16         ` Andreas Rheinhardt
2022-06-28  5:25           ` Soft Works [this message]
2022-06-27  4:18       ` [FFmpeg-devel] [PATCH v4 0/6] " Xiang, Haihao
2022-07-01 20:48       ` [FFmpeg-devel] [PATCH v5 " ffmpegagent
2022-07-01 20:48         ` [FFmpeg-devel] [PATCH v5 1/6] avutil/frame: Add av_frame_copy_side_data() and av_frame_remove_all_side_data() softworkz
2022-07-01 20:48         ` [FFmpeg-devel] [PATCH v5 2/6] avcodec/vpp_qsv: Copy side data from input to output frame softworkz
2022-07-01 20:48         ` [FFmpeg-devel] [PATCH v5 3/6] avcodec/mpeg12dec: make mpeg_decode_user_data() accessible softworkz
2022-07-01 20:48         ` [FFmpeg-devel] [PATCH v5 4/6] avcodec/hevcdec: make set_side_data() accessible softworkz
2022-07-01 20:48         ` [FFmpeg-devel] [PATCH v5 5/6] avcodec/h264dec: make h264_export_frame_props() accessible softworkz
2022-07-01 20:48         ` [FFmpeg-devel] [PATCH v5 6/6] avcodec/qsvdec: Implement SEI parsing for QSV decoders softworkz
2022-07-19  6:55         ` [FFmpeg-devel] [PATCH v5 0/6] " Xiang, Haihao
2022-07-21 21:06           ` Soft Works
2022-07-21 21:56           ` Andreas Rheinhardt
2022-10-21  7:42             ` Soft Works
2022-10-25  4:03         ` [FFmpeg-devel] [PATCH v6 0/3] " ffmpegagent
2022-10-25  4:03           ` [FFmpeg-devel] [PATCH v6 1/3] avcodec/hevcdec: factor out ff_hevc_set_set_to_frame softworkz
2022-10-25  4:03           ` [FFmpeg-devel] [PATCH v6 2/3] avcodec/h264dec: make h264_export_frame_props() accessible softworkz
2022-10-25  4:03           ` [FFmpeg-devel] [PATCH v6 3/3] avcodec/qsvdec: Implement SEI parsing for QSV decoders softworkz
2022-11-21  2:44             ` Xiang, Haihao
2022-11-21 15:58               ` Soft Works
2022-11-22  5:41                 ` Xiang, Haihao
2022-06-01 19:15 ` [FFmpeg-devel] [PATCH 0/6] " Kieran Kunhya
2022-06-01 19:46   ` Soft Works
2022-06-01 20:25     ` Kieran Kunhya
2022-06-01 21:24       ` Soft Works

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DM8P223MB03655121F25A223E7F3F118CBAB89@DM8P223MB0365.NAMP223.PROD.OUTLOOK.COM \
    --to=softworkz@hotmail.com \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git