static void close_encoder(EncoderContext *ec) { flush_frames(ec); av_write_trailer(ec->oc); close_stream(ec->oc, &(ec->video_st)); avio_closep(&(ec->oc->pb)); }
static int recreate_video_proc(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; HRESULT hr; destroy_video_proc(vf); D3D11_VIDEO_PROCESSOR_CONTENT_DESC vpdesc = { .InputFrameFormat = p->d3d_frame_format, .InputWidth = p->c_w, .InputHeight = p->c_h, .OutputWidth = p->params.w, .OutputHeight = p->params.h, }; hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(p->video_dev, &vpdesc, &p->vp_enum); if (FAILED(hr)) goto fail; D3D11_VIDEO_PROCESSOR_CAPS caps; hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(p->vp_enum, &caps); if (FAILED(hr)) goto fail; MP_VERBOSE(vf, "Found %d rate conversion caps. Looking for caps=0x%x.\n", (int)caps.RateConversionCapsCount, p->mode); int rindex = -1; for (int n = 0; n < caps.RateConversionCapsCount; n++) { D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS rcaps; hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorRateConversionCaps (p->vp_enum, n, &rcaps); if (FAILED(hr)) goto fail; MP_VERBOSE(vf, " - %d: 0x%08x\n", n, (unsigned)rcaps.ProcessorCaps); if (rcaps.ProcessorCaps & p->mode) { MP_VERBOSE(vf, " (matching)\n"); if (rindex < 0) rindex = n; } } if (rindex < 0) { MP_WARN(vf, "No fitting video processor found, picking #0.\n"); rindex = 0; } // TOOD: so, how do we select which rate conversion mode the processor uses? hr = ID3D11VideoDevice_CreateVideoProcessor(p->video_dev, p->vp_enum, rindex, &p->video_proc); if (FAILED(hr)) { MP_ERR(vf, "Failed to create D3D11 video processor.\n"); goto fail; } // Note: libavcodec does not support cropping left/top with hwaccel. RECT src_rc = { .right = p->params.w, .bottom = p->params.h, }; ID3D11VideoContext_VideoProcessorSetStreamSourceRect(p->video_ctx, p->video_proc, 0, TRUE, &src_rc); // This is supposed to stop drivers from f*****g up the video quality. ID3D11VideoContext_VideoProcessorSetStreamAutoProcessingMode(p->video_ctx, p->video_proc, 0, FALSE); ID3D11VideoContext_VideoProcessorSetStreamOutputRate(p->video_ctx, p->video_proc, 0, D3D11_VIDEO_PROCESSOR_OUTPUT_RATE_NORMAL, FALSE, 0); D3D11_VIDEO_PROCESSOR_COLOR_SPACE csp = { .YCbCr_Matrix = p->params.color.space != MP_CSP_BT_601, .Nominal_Range = p->params.color.levels == MP_CSP_LEVELS_TV ? 1 : 2, }; ID3D11VideoContext_VideoProcessorSetStreamColorSpace(p->video_ctx, p->video_proc, 0, &csp); if (p->out_rgb) { if (p->params.color.space != MP_CSP_BT_601 && p->params.color.space != MP_CSP_BT_709) { MP_WARN(vf, "Unsupported video colorspace (%s/%s). Consider " "disabling hardware decoding, or using " "--hwdec=d3d11va-copy to get correct output.\n", m_opt_choice_str(mp_csp_names, p->params.color.space), m_opt_choice_str(mp_csp_levels_names, p->params.color.levels)); } } else { ID3D11VideoContext_VideoProcessorSetOutputColorSpace(p->video_ctx, p->video_proc, &csp); } return 0; fail: destroy_video_proc(vf); return -1; } static int render(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; int res = -1; HRESULT hr; ID3D11VideoProcessorInputView *in_view = NULL; ID3D11VideoProcessorOutputView *out_view = NULL; struct mp_image *in = NULL, *out = NULL; out = mp_image_pool_get(p->pool, p->out_params.imgfmt, p->params.w, p->params.h); if (!out) goto cleanup; ID3D11Texture2D *d3d_out_tex = (void *)out->planes[1]; in = mp_refqueue_get(p->queue, 0); if (!in) goto cleanup; ID3D11Texture2D *d3d_tex = (void *)in->planes[1]; int d3d_subindex = (intptr_t)in->planes[2]; mp_image_copy_attributes(out, in); D3D11_VIDEO_FRAME_FORMAT d3d_frame_format; if (!mp_refqueue_should_deint(p->queue)) { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; } else if (mp_refqueue_top_field_first(p->queue)) { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST; } else { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST; } D3D11_TEXTURE2D_DESC texdesc; ID3D11Texture2D_GetDesc(d3d_tex, &texdesc); if (!p->video_proc || p->c_w != texdesc.Width || p->c_h != texdesc.Height || p->d3d_frame_format != d3d_frame_format) { p->c_w = texdesc.Width; p->c_h = texdesc.Height; p->d3d_frame_format = d3d_frame_format; if (recreate_video_proc(vf) < 0) goto cleanup; } if (!mp_refqueue_should_deint(p->queue)) { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; } else if (mp_refqueue_is_top_field(p->queue)) { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST; } else { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST; } ID3D11VideoContext_VideoProcessorSetStreamFrameFormat(p->video_ctx, p->video_proc, 0, d3d_frame_format); D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC indesc = { .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D, .Texture2D = { .ArraySlice = d3d_subindex, }, }; hr = ID3D11VideoDevice_CreateVideoProcessorInputView(p->video_dev, (ID3D11Resource *)d3d_tex, p->vp_enum, &indesc, &in_view); if (FAILED(hr)) { MP_ERR(vf, "Could not create ID3D11VideoProcessorInputView\n"); goto cleanup; } D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outdesc = { .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D, }; hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(p->video_dev, (ID3D11Resource *)d3d_out_tex, p->vp_enum, &outdesc, &out_view); if (FAILED(hr)) goto cleanup; D3D11_VIDEO_PROCESSOR_STREAM stream = { .Enable = TRUE, .pInputSurface = in_view, }; int frame = mp_refqueue_is_second_field(p->queue); hr = ID3D11VideoContext_VideoProcessorBlt(p->video_ctx, p->video_proc, out_view, frame, 1, &stream); if (FAILED(hr)) { MP_ERR(vf, "VideoProcessorBlt failed.\n"); goto cleanup; } res = 0; cleanup: if (in_view) ID3D11VideoProcessorInputView_Release(in_view); if (out_view) ID3D11VideoProcessorOutputView_Release(out_view); if (res >= 0) { vf_add_output_frame(vf, out); } else { talloc_free(out); } mp_refqueue_next_field(p->queue); return res; } static int filter_out(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; if (!mp_refqueue_has_output(p->queue)) return 0; // no filtering if (!mp_refqueue_should_deint(p->queue) && !p->require_filtering) { struct mp_image *in = mp_image_new_ref(mp_refqueue_get(p->queue, 0)); if (!in) return -1; mp_image_set_params(in, &p->out_params); vf_add_output_frame(vf, in); mp_refqueue_next(p->queue); return 0; } return render(vf); } static int reconfig(struct vf_instance *vf, struct mp_image_params *in, struct mp_image_params *out) { struct vf_priv_s *p = vf->priv; flush_frames(vf); talloc_free(p->pool); p->pool = NULL; destroy_video_proc(vf); *out = *in; if (vf_next_query_format(vf, IMGFMT_D3D11VA) || vf_next_query_format(vf, IMGFMT_D3D11NV12)) { out->imgfmt = vf_next_query_format(vf, IMGFMT_D3D11VA) ? IMGFMT_D3D11VA : IMGFMT_D3D11NV12; out->hw_subfmt = IMGFMT_NV12; p->out_format = DXGI_FORMAT_NV12; p->out_shared = false; p->out_rgb = false; } else { out->imgfmt = IMGFMT_D3D11RGB; out->hw_subfmt = IMGFMT_RGB0; p->out_format = DXGI_FORMAT_B8G8R8A8_UNORM; p->out_shared = true; p->out_rgb = true; } p->require_filtering = in->hw_subfmt != out->hw_subfmt; p->params = *in; p->out_params = *out; p->pool = mp_image_pool_new(20); mp_image_pool_set_allocator(p->pool, alloc_pool, vf); mp_image_pool_set_lru(p->pool); return 0; } static void uninit(struct vf_instance *vf) { struct vf_priv_s *p = vf->priv; destroy_video_proc(vf); flush_frames(vf); mp_refqueue_free(p->queue); talloc_free(p->pool); if (p->video_ctx) ID3D11VideoContext_Release(p->video_ctx); if (p->video_dev) ID3D11VideoDevice_Release(p->video_dev); if (p->device_ctx) ID3D11DeviceContext_Release(p->device_ctx); if (p->vo_dev) ID3D11Device_Release(p->vo_dev); } static int query_format(struct vf_instance *vf, unsigned int imgfmt) { if (imgfmt == IMGFMT_D3D11VA || imgfmt == IMGFMT_D3D11NV12 || imgfmt == IMGFMT_D3D11RGB) { return vf_next_query_format(vf, IMGFMT_D3D11VA) || vf_next_query_format(vf, IMGFMT_D3D11NV12) || vf_next_query_format(vf, IMGFMT_D3D11RGB); } return 0; } static bool test_conversion(int in, int out) { return (in == IMGFMT_D3D11VA || in == IMGFMT_D3D11NV12 || in == IMGFMT_D3D11RGB) && (out == IMGFMT_D3D11VA || out == IMGFMT_D3D11NV12 || out == IMGFMT_D3D11RGB); } static int control(struct vf_instance *vf, int request, void* data) { struct vf_priv_s *p = vf->priv; switch (request){ case VFCTRL_GET_DEINTERLACE: *(int*)data = !!p->deint_enabled; return true; case VFCTRL_SET_DEINTERLACE: p->deint_enabled = !!*(int*)data; return true; case VFCTRL_SEEK_RESET: flush_frames(vf); return true; default: return CONTROL_UNKNOWN; } } static int vf_open(vf_instance_t *vf) { struct vf_priv_s *p = vf->priv; vf->reconfig = reconfig; vf->filter_ext = filter_ext; vf->filter_out = filter_out; vf->query_format = query_format; vf->uninit = uninit; vf->control = control; p->queue = mp_refqueue_alloc(); p->vo_dev = hwdec_devices_load(vf->hwdec_devs, HWDEC_D3D11VA); if (!p->vo_dev) return 0; ID3D11Device_AddRef(p->vo_dev); HRESULT hr; hr = ID3D11Device_QueryInterface(p->vo_dev, &IID_ID3D11VideoDevice, (void **)&p->video_dev); if (FAILED(hr)) goto fail; ID3D11Device_GetImmediateContext(p->vo_dev, &p->device_ctx); if (!p->device_ctx) goto fail; hr = ID3D11DeviceContext_QueryInterface(p->device_ctx, &IID_ID3D11VideoContext, (void **)&p->video_ctx); if (FAILED(hr)) goto fail; return 1; fail: uninit(vf); return 0; } #define OPT_BASE_STRUCT struct vf_priv_s static const m_option_t vf_opts_fields[] = { OPT_FLAG("deint", deint_enabled, 0), OPT_FLAG("interlaced-only", interlaced_only, 0), OPT_CHOICE("mode", mode, 0, ({"blend", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BLEND}, {"bob", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB}, {"adaptive", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_ADAPTIVE}, {"mocomp", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_MOTION_COMPENSATION},
static int recreate_video_proc(struct mp_filter *vf) { struct priv *p = vf->priv; HRESULT hr; destroy_video_proc(vf); D3D11_VIDEO_PROCESSOR_CONTENT_DESC vpdesc = { .InputFrameFormat = p->d3d_frame_format, .InputWidth = p->c_w, .InputHeight = p->c_h, .OutputWidth = p->params.w, .OutputHeight = p->params.h, }; hr = ID3D11VideoDevice_CreateVideoProcessorEnumerator(p->video_dev, &vpdesc, &p->vp_enum); if (FAILED(hr)) goto fail; D3D11_VIDEO_PROCESSOR_CAPS caps; hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorCaps(p->vp_enum, &caps); if (FAILED(hr)) goto fail; MP_VERBOSE(vf, "Found %d rate conversion caps. Looking for caps=0x%x.\n", (int)caps.RateConversionCapsCount, p->opts->mode); int rindex = -1; for (int n = 0; n < caps.RateConversionCapsCount; n++) { D3D11_VIDEO_PROCESSOR_RATE_CONVERSION_CAPS rcaps; hr = ID3D11VideoProcessorEnumerator_GetVideoProcessorRateConversionCaps (p->vp_enum, n, &rcaps); if (FAILED(hr)) goto fail; MP_VERBOSE(vf, " - %d: 0x%08x\n", n, (unsigned)rcaps.ProcessorCaps); if (rcaps.ProcessorCaps & p->opts->mode) { MP_VERBOSE(vf, " (matching)\n"); if (rindex < 0) rindex = n; } } if (rindex < 0) { MP_WARN(vf, "No fitting video processor found, picking #0.\n"); rindex = 0; } // TOOD: so, how do we select which rate conversion mode the processor uses? hr = ID3D11VideoDevice_CreateVideoProcessor(p->video_dev, p->vp_enum, rindex, &p->video_proc); if (FAILED(hr)) { MP_ERR(vf, "Failed to create D3D11 video processor.\n"); goto fail; } // Note: libavcodec does not support cropping left/top with hwaccel. RECT src_rc = { .right = p->params.w, .bottom = p->params.h, }; ID3D11VideoContext_VideoProcessorSetStreamSourceRect(p->video_ctx, p->video_proc, 0, TRUE, &src_rc); // This is supposed to stop drivers from f*****g up the video quality. ID3D11VideoContext_VideoProcessorSetStreamAutoProcessingMode(p->video_ctx, p->video_proc, 0, FALSE); ID3D11VideoContext_VideoProcessorSetStreamOutputRate(p->video_ctx, p->video_proc, 0, D3D11_VIDEO_PROCESSOR_OUTPUT_RATE_NORMAL, FALSE, 0); D3D11_VIDEO_PROCESSOR_COLOR_SPACE csp = { .YCbCr_Matrix = p->params.color.space != MP_CSP_BT_601, .Nominal_Range = p->params.color.levels == MP_CSP_LEVELS_TV ? 1 : 2, }; ID3D11VideoContext_VideoProcessorSetStreamColorSpace(p->video_ctx, p->video_proc, 0, &csp); if (p->out_rgb) { if (p->params.color.space != MP_CSP_BT_601 && p->params.color.space != MP_CSP_BT_709) { MP_WARN(vf, "Unsupported video colorspace (%s/%s). Consider " "disabling hardware decoding, or using " "--hwdec=d3d11va-copy to get correct output.\n", m_opt_choice_str(mp_csp_names, p->params.color.space), m_opt_choice_str(mp_csp_levels_names, p->params.color.levels)); } } else { ID3D11VideoContext_VideoProcessorSetOutputColorSpace(p->video_ctx, p->video_proc, &csp); } return 0; fail: destroy_video_proc(vf); return -1; } static struct mp_image *render(struct mp_filter *vf) { struct priv *p = vf->priv; int res = -1; HRESULT hr; ID3D11VideoProcessorInputView *in_view = NULL; ID3D11VideoProcessorOutputView *out_view = NULL; struct mp_image *in = NULL, *out = NULL; out = mp_image_pool_get(p->pool, IMGFMT_D3D11, p->params.w, p->params.h); if (!out) { MP_WARN(vf, "failed to allocate frame\n"); goto cleanup; } ID3D11Texture2D *d3d_out_tex = (void *)out->planes[0]; in = mp_refqueue_get(p->queue, 0); if (!in) goto cleanup; ID3D11Texture2D *d3d_tex = (void *)in->planes[0]; int d3d_subindex = (intptr_t)in->planes[1]; mp_image_copy_attributes(out, in); D3D11_VIDEO_FRAME_FORMAT d3d_frame_format; if (!mp_refqueue_should_deint(p->queue)) { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; } else if (mp_refqueue_top_field_first(p->queue)) { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST; } else { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST; } D3D11_TEXTURE2D_DESC texdesc; ID3D11Texture2D_GetDesc(d3d_tex, &texdesc); if (!p->video_proc || p->c_w != texdesc.Width || p->c_h != texdesc.Height || p->d3d_frame_format != d3d_frame_format) { p->c_w = texdesc.Width; p->c_h = texdesc.Height; p->d3d_frame_format = d3d_frame_format; if (recreate_video_proc(vf) < 0) goto cleanup; } if (!mp_refqueue_should_deint(p->queue)) { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE; } else if (mp_refqueue_is_top_field(p->queue)) { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_TOP_FIELD_FIRST; } else { d3d_frame_format = D3D11_VIDEO_FRAME_FORMAT_INTERLACED_BOTTOM_FIELD_FIRST; } ID3D11VideoContext_VideoProcessorSetStreamFrameFormat(p->video_ctx, p->video_proc, 0, d3d_frame_format); D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC indesc = { .ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D, .Texture2D = { .ArraySlice = d3d_subindex, }, }; hr = ID3D11VideoDevice_CreateVideoProcessorInputView(p->video_dev, (ID3D11Resource *)d3d_tex, p->vp_enum, &indesc, &in_view); if (FAILED(hr)) { MP_ERR(vf, "Could not create ID3D11VideoProcessorInputView\n"); goto cleanup; } D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC outdesc = { .ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D, }; hr = ID3D11VideoDevice_CreateVideoProcessorOutputView(p->video_dev, (ID3D11Resource *)d3d_out_tex, p->vp_enum, &outdesc, &out_view); if (FAILED(hr)) { MP_ERR(vf, "Could not create ID3D11VideoProcessorOutputView\n"); goto cleanup; } D3D11_VIDEO_PROCESSOR_STREAM stream = { .Enable = TRUE, .pInputSurface = in_view, }; int frame = mp_refqueue_is_second_field(p->queue); hr = ID3D11VideoContext_VideoProcessorBlt(p->video_ctx, p->video_proc, out_view, frame, 1, &stream); if (FAILED(hr)) { MP_ERR(vf, "VideoProcessorBlt failed.\n"); goto cleanup; } res = 0; cleanup: if (in_view) ID3D11VideoProcessorInputView_Release(in_view); if (out_view) ID3D11VideoProcessorOutputView_Release(out_view); if (res < 0) TA_FREEP(&out); return out; } static bool vo_supports(struct priv *p, int subfmt) { for (int n = 0; p->vo_formats && p->vo_formats[n]; n++) { if (p->vo_formats[n] == subfmt) return true; } return false; } static void vf_d3d11vpp_process(struct mp_filter *vf) { struct priv *p = vf->priv; struct mp_image *in_fmt = mp_refqueue_execute_reinit(p->queue); if (in_fmt) { mp_image_pool_clear(p->pool); destroy_video_proc(vf); p->params = in_fmt->params; p->out_params = p->params; if (vo_supports(p, IMGFMT_NV12)) { p->out_params.hw_subfmt = IMGFMT_NV12; p->out_format = DXGI_FORMAT_NV12; p->out_shared = false; p->out_rgb = false; } else { p->out_params.hw_subfmt = IMGFMT_RGB0; p->out_format = DXGI_FORMAT_B8G8R8A8_UNORM; p->out_shared = true; p->out_rgb = true; } p->out_params.hw_flags = 0; p->require_filtering = p->params.hw_subfmt != p->out_params.hw_subfmt; } if (!mp_refqueue_can_output(p->queue)) return; if (!mp_refqueue_should_deint(p->queue) && !p->require_filtering) { // no filtering struct mp_image *in = mp_image_new_ref(mp_refqueue_get(p->queue, 0)); if (!in) { mp_filter_internal_mark_failed(vf); return; } mp_refqueue_write_out_pin(p->queue, in); } else { mp_refqueue_write_out_pin(p->queue, render(vf)); } } static void uninit(struct mp_filter *vf) { struct priv *p = vf->priv; destroy_video_proc(vf); flush_frames(vf); talloc_free(p->queue); talloc_free(p->pool); if (p->video_ctx) ID3D11VideoContext_Release(p->video_ctx); if (p->video_dev) ID3D11VideoDevice_Release(p->video_dev); if (p->device_ctx) ID3D11DeviceContext_Release(p->device_ctx); if (p->vo_dev) ID3D11Device_Release(p->vo_dev); } static const struct mp_filter_info vf_d3d11vpp_filter = { .name = "d3d11vpp", .process = vf_d3d11vpp_process, .reset = flush_frames, .destroy = uninit, .priv_size = sizeof(struct priv), }; static struct mp_filter *vf_d3d11vpp_create(struct mp_filter *parent, void *options) { struct mp_filter *f = mp_filter_create(parent, &vf_d3d11vpp_filter); if (!f) { talloc_free(options); return NULL; } mp_filter_add_pin(f, MP_PIN_IN, "in"); mp_filter_add_pin(f, MP_PIN_OUT, "out"); struct priv *p = f->priv; p->opts = talloc_steal(p, options); // Special path for vf_d3d11_create_outconv(): disable all processing except // possibly surface format conversions. if (!p->opts) { static const struct opts opts = {0}; p->opts = (struct opts *)&opts; } p->queue = mp_refqueue_alloc(f); struct mp_stream_info *info = mp_filter_find_stream_info(f); if (!info || !info->hwdec_devs) goto fail; hwdec_devices_request_all(info->hwdec_devs); struct mp_hwdec_ctx *hwctx = hwdec_devices_get_by_lavc(info->hwdec_devs, AV_HWDEVICE_TYPE_D3D11VA); if (!hwctx || !hwctx->av_device_ref) goto fail; AVHWDeviceContext *avhwctx = (void *)hwctx->av_device_ref->data; AVD3D11VADeviceContext *d3dctx = avhwctx->hwctx; p->vo_dev = d3dctx->device; ID3D11Device_AddRef(p->vo_dev); p->vo_formats = hwctx->supported_formats; HRESULT hr; hr = ID3D11Device_QueryInterface(p->vo_dev, &IID_ID3D11VideoDevice, (void **)&p->video_dev); if (FAILED(hr)) goto fail; ID3D11Device_GetImmediateContext(p->vo_dev, &p->device_ctx); if (!p->device_ctx) goto fail; hr = ID3D11DeviceContext_QueryInterface(p->device_ctx, &IID_ID3D11VideoContext, (void **)&p->video_ctx); if (FAILED(hr)) goto fail; p->pool = mp_image_pool_new(f); mp_image_pool_set_allocator(p->pool, alloc_pool, f); mp_image_pool_set_lru(p->pool); mp_refqueue_add_in_format(p->queue, IMGFMT_D3D11, 0); mp_refqueue_set_refs(p->queue, 0, 0); mp_refqueue_set_mode(p->queue, (p->opts->deint_enabled ? MP_MODE_DEINT : 0) | MP_MODE_OUTPUT_FIELDS | (p->opts->interlaced_only ? MP_MODE_INTERLACED_ONLY : 0)); return f; fail: talloc_free(f); return NULL; } #define OPT_BASE_STRUCT struct opts static const m_option_t vf_opts_fields[] = { OPT_FLAG("deint", deint_enabled, 0), OPT_FLAG("interlaced-only", interlaced_only, 0), OPT_CHOICE("mode", mode, 0, ({"blend", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BLEND}, {"bob", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_BOB}, {"adaptive", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_ADAPTIVE}, {"mocomp", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_DEINTERLACE_MOTION_COMPENSATION}, {"ivctc", D3D11_VIDEO_PROCESSOR_PROCESSOR_CAPS_INVERSE_TELECINE},
int mpeg4_p2_video_packetizer_c::process_non_native(packet_cptr packet) { extract_config_data(packet); // Add a timecode and a duration if they've been given. if (-1 != packet->timecode) { if (!m_default_duration_forced) m_available_timecodes.push_back(timecode_duration_t(packet->timecode, packet->duration)); else { m_available_timecodes.push_back(timecode_duration_t(m_timecodes_generated * m_htrack_default_duration, m_htrack_default_duration)); ++m_timecodes_generated; } } else if (0.0 == m_fps) mxerror_tid(m_ti.m_fname, m_ti.m_id, Y("Cannot convert non-native MPEG4 video frames into native ones if the source container " "provides neither timecodes nor a number of frames per second.\n")); std::vector<video_frame_t> frames; mpeg4::p2::find_frame_types(packet->data->get_buffer(), packet->data->get_size(), frames, m_config_data); for (auto &frame : frames) { if (!frame.is_coded) { ++m_statistics.m_num_n_vops; int num_surplus_timecodes = static_cast<int>(m_available_timecodes.size()) - static_cast<int>(m_ref_frames.size() + m_b_frames.size()); if (0 < num_surplus_timecodes) { std::deque<timecode_duration_t>::iterator start = m_available_timecodes.begin() + m_ref_frames.size() + m_b_frames.size(); std::deque<timecode_duration_t>::iterator end = start + num_surplus_timecodes; if (0 != (m_ref_frames.size() + m_b_frames.size())) { std::deque<timecode_duration_t>::iterator last = m_available_timecodes.begin() + m_ref_frames.size() + m_b_frames.size() - 1; std::deque<timecode_duration_t>::iterator cur = start; while (cur != end) { last->m_duration = std::max(last->m_duration, static_cast<int64_t>(0)) + std::max(cur->m_duration, static_cast<int64_t>(0)); ++cur; } } m_available_timecodes.erase(start, end); m_statistics.m_num_dropped_timecodes += num_surplus_timecodes; } continue; } if (FRAME_TYPE_I == frame.type) ++m_statistics.m_num_i_frames; else if (FRAME_TYPE_P == frame.type) ++m_statistics.m_num_p_frames; else ++m_statistics.m_num_b_frames; // Maybe we can flush queued frames now. But only if we don't have // a B frame. if (FRAME_TYPE_B != frame.type) flush_frames(false); frame.data = (unsigned char *)safememdup(packet->data->get_buffer() + frame.pos, frame.size); frame.timecode = -1; if (FRAME_TYPE_B == frame.type) m_b_frames.push_back(frame); else m_ref_frames.push_back(frame); } m_previous_timecode = m_available_timecodes.back().m_timecode; return FILE_STATUS_MOREDATA; }
void mpeg4_p2_video_packetizer_c::flush_impl() { flush_frames(true); }
int main(int argc, char* argv[]) { // Checks the program parameters int opt; map_options(argc, argv, &opt); argc -= optind; argv += optind; if(argc != 2) { usage(); exit(EXIT_FAILURE); } // Destination file opening if(fd == -1) { if((fd = open(filename, O_RDWR|O_CREAT, S_IRWXU|S_IRWXG)) < 0) { die("Error opening destination file"); } } // Port and adresses string init char *addr_str = argv[0]; char *port_str = argv[1]; if(verbose) { printf("\nListenning address \'%s\' on port \'%s\'\n", addr_str, port_str); } // Resolve the address passed to the program int result; if((result = getaddrinfo(addr_str, port_str, &hints, &address)) < 0) { printf("Error resolving address %s - code %i", addr_str, result); freeaddrinfo(address); close(fd); exit(EXIT_FAILURE); } // initialize the socket used by the receiver sock_id = init_host(address, receiver); if(sock_id == -1) { die("Error creating socket"); } packetstruct tmp_packet; // stores the just received packet // last in-sequence acknowledge packet int lastack = SEQSPAN-1; // last in-sequence acknowledge packet int bufferPos = 0; // Position following lastack in the buffer // of paylod has been received. int bufferFill = 0; //nb of unwritten valid packets received int idx; //position in the buffer for the received packet ssize_t size = PAYLOADSIZE; // Size of the received payload int is_valid; memset(window,0,BUFFSIZE*sizeof(window_slot)); while( !isReceived(lastack) ) { /* blocking receive - we are waiting for a frame */ src_len = sizeof(src_host); if(recvfrom(sock_id, (void *) &tmp_packet, sizeof(tmp_packet), 0, (struct sockaddr*) &src_host, &(src_len)) != sizeof(packetstruct)) { die("Error while receiving packet"); } is_valid = packet_valid(&tmp_packet); /* only if the packet is valid */ if(is_valid == 1) { size = tmp_packet.length; if(verbose) { printf("Received a %zd-byte type %u packet (seq %u)\n", size, tmp_packet.type, tmp_packet.seqnum); } // Is the sequence number in the receive window ? if((idx = idx_in_window(tmp_packet.seqnum,lastack,bufferPos)) != -1) { if(bufferFill<BUFFSIZE && !window[idx].received){ recv_buffer[idx] = tmp_packet; // copy packet to rcv_buffer window[idx].received = true; // mark the frame as received bufferFill++; // add 1 more received packet /* If this is the last packet from the original file * (ie, payload with a size smaller than 512 Bytes */ if(size < PAYLOADSIZE) { if(verbose){ printf("Packet with smaller PAYLOADSIZE received, end of file detected\n"); } lastseq = tmp_packet.seqnum; } // Try to empty the in-sequence received packets if(flush_frames(fd, &lastack, &bufferPos, &bufferFill)) { die("Error writing packets to file"); } } else{printf("BufferFill : %d The receiving buffer is full\n",bufferFill);} // Send an acknowledgement acknowledge(lastack); } // Else, we do nothing and discard it... else if(verbose) { printf("Received an out-of-window packet (seq:%u)(lastack:%d)\n ", tmp_packet.seqnum,lastack); } } else{ if(verbose){ printf("Received a corrupted packet !\n"); } acknowledge(lastack); } } // End of transmission : resend acks if the sender keeps sending data int received; int timeDiff = EOTDELAY-1; int EOTstart = clock(); while(timeDiff<EOTDELAY){ received = 0; fcntl(sock_id, F_SETFL, O_NONBLOCK); // make receive non-blocking received = recvfrom(sock_id,(void*)(&tmp_packet),sizeof(tmp_packet),0,NULL,NULL); if(received != sizeof(packetstruct) && errno != EAGAIN) { die("Error receiving"); } if(received==sizeof(packetstruct)){ acknowledge(lastack); } timeDiff = (clock()-EOTstart)*1000/CLOCKS_PER_SEC; } if(verbose) { printf("File successfully received\n"); } freeaddrinfo(address); close(sock_id); exit(EXIT_SUCCESS); }