Repository: abhiTronix/deffcode (language: python)

Issue:
[Idea]: Discarding default FFmpeg parameters and using FFmpeg Filters instead.
### Issue guidelines

- [X] I've read the [Issue Guidelines](https://abhitronix.github.io/deffcode/latest/contribution/issue/#submitting-an-issue-guidelines) and wholeheartedly agree.

### Issue Checklist

- [X] I have searched open or closed [issues](https://github.com/abhiTronix/deffcode/issues) and found nothing related to my idea.
- [X] I have read the [Documentation](https://abhitronix.github.io/deffcode/latest) and it doesn't mention anything about my idea.
- [X] To my best knowledge, my idea wouldn't break something for other users.

### Describe your Idea

This idea targets two problem that currently DeFFcode APIs fails to address:

1. **Discarding default FFmpeg parameters:** Certain default FFmpeg parameters in DeFFcode API such as  `-framerate`, `-pix_fmt`, `-size` cannot be removed/discarded from Decoding Pipeline in any way possible, and thereby present in every Pipeline that DeFFcode API has ever created. These parameters were thought to be extremely necessary for Pipeline to work but my recent tests shown that even if we remove these parameters the Decoding pipeline _(with some changes)_ works totally fine. And instead, FFmpeg itself handles these parameter in best possible manner based on source and decoder provided by the user.
2. **Using FFmpeg Filters:** Currently DeFFcode APIs fails to recognize values from filters like `fps`, `format`, `scale` which tends to break the pipeline with artifacts appearing on the output frames. This is due to fact that `-framerate`, `-pix_fmt`, `-size` like parameter are given advantage over filters values by the DeFFCode APIs and was primarily used by them to decode frames. For example if we `scale=320:240` filter as follows, the output will be improper(with artifacts) since API tries to use FFmpeg parameter `-s` i.e. equal to source video frame size(for e.g. `1920x1080`) which is way higher than require `320x240` as defined by the filter:

    ```python
    # import the necessary packages
    from deffcode import FFdecoder
    import cv2

    # define params and custom filters
    ffparams = {
        "-vf": "scale=320:240",  # framerate=60fps
    }

    # initialize and formulate the decoder with params and custom filters
    decoder = FFdecoder(
        "t.mp4", frame_format="bgr24", verbose=True, **ffparams
    ).formulate()

    # grab the BGR24 frames from decoder
    for frame in decoder.generateFrame():

        # check if frame is None
        if frame is None:
            break

        # {do something with the frame here}

        # Show output window
        cv2.imshow("Invalid Output", frame)

        # check for 'q' key if pressed
        key = cv2.waitKey(1) & 0xFF
        if key == ord("q"):
            break

    # close output window
    cv2.destroyAllWindows()

    # terminate the decoder
    decoder.terminate()
    ```


### Use Cases

Both Discarding default FFmpeg parameters and using FFmpeg Filters, are absolute necessity for decoding/transcoding video frames in GPU, as with FFmpeg commands like `ffmpeg -y -vsync 0 -hwaccel_output_format cuda -hwaccel cuda -c:v h264_cuvid -i input.mp4 -vf "scale_npp=format=yuv420p,hwdownload,format=yuv420p,fps=25.0" -f rawvideo -` fails to work with FFmpeg parameters `-framerate`, `-pix_fmt`, `-size`  and throws `Impossible to convert between the formats supported by the filter 'Parsed_null_0' and the filter 'auto_scale_0' Error reinitializing filters! Failed to inject frame into filter network: Function not implemented` error. **Therefore, implementing both these features will resolves issue with decoding/transcoding with DeFFcode APIs automatically _(thus resolving #30)_.**

### Any other Relevant Information?

_No response_
[Idea]: Discarding default FFmpeg parameters and using FFmpeg Filters instead.
### Issue guidelines

- [X] I've read the [Issue Guidelines](https://abhitronix.github.io/deffcode/latest/contribution/issue/#submitting-an-issue-guidelines) and wholeheartedly agree.

### Issue Checklist

- [X] I have searched open or closed [issues](https://github.com/abhiTronix/deffcode/issues) and found nothing related to my idea.
- [X] I have read the [Documentation](https://abhitronix.github.io/deffcode/latest) and it doesn't mention anything about my idea.
- [X] To my best knowledge, my idea wouldn't break something for other users.

### Describe your Idea

This idea targets two problem that currently DeFFcode APIs fails to address:

1. **Discarding default FFmpeg parameters:** Certain default FFmpeg parameters in DeFFcode API such as  `-framerate`, `-pix_fmt`, `-size` cannot be removed/discarded from Decoding Pipeline in any way possible, and thereby present in every Pipeline that DeFFcode API has ever created. These parameters were thought to be extremely necessary for Pipeline to work but my recent tests shown that even if we remove these parameters the Decoding pipeline _(with some changes)_ works totally fine. And instead, FFmpeg itself handles these parameter in best possible manner based on source and decoder provided by the user.
2. **Using FFmpeg Filters:** Currently DeFFcode APIs fails to recognize values from filters like `fps`, `format`, `scale` which tends to break the pipeline with artifacts appearing on the output frames. This is due to fact that `-framerate`, `-pix_fmt`, `-size` like parameter are given advantage over filters values by the DeFFCode APIs and was primarily used by them to decode frames. For example if we `scale=320:240` filter as follows, the output will be improper(with artifacts) since API tries to use FFmpeg parameter `-s` i.e. equal to source video frame size(for e.g. `1920x1080`) which is way higher than require `320x240` as defined by the filter:

    ```python
    # import the necessary packages
    from deffcode import FFdecoder
    import cv2

    # define params and custom filters
    ffparams = {
        "-vf": "scale=320:240",  # framerate=60fps
    }

    # initialize and formulate the decoder with params and custom filters
    decoder = FFdecoder(
        "t.mp4", frame_format="bgr24", verbose=True, **ffparams
    ).formulate()

    # grab the BGR24 frames from decoder
    for frame in decoder.generateFrame():

        # check if frame is None
        if frame is None:
            break

        # {do something with the frame here}

        # Show output window
        cv2.imshow("Invalid Output", frame)

        # check for 'q' key if pressed
        key = cv2.waitKey(1) & 0xFF
        if key == ord("q"):
            break

    # close output window
    cv2.destroyAllWindows()

    # terminate the decoder
    decoder.terminate()
    ```


### Use Cases

Both Discarding default FFmpeg parameters and using FFmpeg Filters, are absolute necessity for decoding/transcoding video frames in GPU, as with FFmpeg commands like `ffmpeg -y -vsync 0 -hwaccel_output_format cuda -hwaccel cuda -c:v h264_cuvid -i input.mp4 -vf "scale_npp=format=yuv420p,hwdownload,format=yuv420p,fps=25.0" -f rawvideo -` fails to work with FFmpeg parameters `-framerate`, `-pix_fmt`, `-size`  and throws `Impossible to convert between the formats supported by the filter 'Parsed_null_0' and the filter 'auto_scale_0' Error reinitializing filters! Failed to inject frame into filter network: Function not implemented` error. **Therefore, implementing both these features will resolves issue with decoding/transcoding with DeFFcode APIs automatically _(thus resolving #30)_.**

### Any other Relevant Information?

_No response_
Can't run the code in  "Hardware-Accelerated Video Transcoding"
### Issue guidelines

- [X] I've read the [Issue Guidelines](https://abhitronix.github.io/deffcode/latest/contribution/issue/#submitting-an-issue-guidelines) and wholeheartedly agree.

### Issue Checklist

- [X] I have searched open or closed [issues](https://github.com/abhiTronix/deffcode/issues) for my problem and found nothing related or helpful.
- [X] I have read the [Documentation](https://abhitronix.github.io/deffcode/latest) and found nothing related to my problem.

### Describe your Question

Hi, Many thanks to you. This project helps me a lot.

I want use my gpu, so I tried the code in "[Hardware-Accelerated Video Transcoding](https://abhitronix.github.io/deffcode/latest/recipes/advanced/transcode-hw-acceleration/#gpu-accelerated-hardware-based-video-transcoding-with-writegear-api)" 

ENV:
```
12:13:25 ::    Utilies    ::   INFO   :: Running DeFFcode Version: 0.2.3
12:13:25 ::    Helper     ::   INFO   :: Running VidGear Version: 0.2.6
```

At first. my ffmpeg already support GPU.
```
$ ffmpeg  -hide_banner -decoders | grep h264
 VFS..D h264                 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
 V..... h264_v4l2m2m         V4L2 mem2mem H.264 decoder wrapper (codec h264)
 V..... h264_cuvid           Nvidia CUVID H264 decoder (codec h264)

$ ffmpeg  -hide_banner -encoders | grep nvenc
 V....D h264_nvenc           NVIDIA NVENC H.264 encoder (codec h264)
 V....D hevc_nvenc           NVIDIA NVENC hevc encoder (codec hevc)
```

But after I copied those codes and run, some errors happened.
1. Seems '-' is a wrong character in "–hwaccel", it should be "-", like "-vsync". They look very similar
2. Con't use ffparams   ("–hwaccel", "cuvid"). The ffmpeg command used by decoder at last is :

 12:21:40 ::   FFdecoder   ::  DEBUG   :: Executing FFmpeg command: `ffmpeg -vsync 0 -hwaccel cuvid -vcodec h264_cuvid -i /data/sport/demo/deffcode_test/Big_Buck_Bunny_1080_10s_1MB.mp4 -pix_fmt bgr24 -s 1920x1080 -framerate 60.0 -f rawvideo -

  But this will have an error: 
```
  Impossible to convert between the formats supported by the filter 'Parsed_null_0' and the filter 'auto_scale_0'
Error reinitializing filters!
Failed to inject frame into filter network: Function not implemented
```
I have checked commands:
```
ffmpeg -vsync 0 -vcodec hevc_cuvid -i /data/sport/auto_directed/ptz_camera/videos/guoxin_h265.mp4 -pix_fmt bgr24 -f rawvideo -

ffmpeg -vsync 0 -hwaccel_output_format cuda -hwaccel cuvid -vcodec hevc_cuvid -i /data/sport/auto_directed/ptz_camera/videos/guoxin_h265.mp4  -pix_fmt bgr24 -f rawvideo -
```
Both commands can be run. But `-hwaccel cuvid` and `-pix_fmt bgr24` con't by used together.

So I removed `-hwaccel cuvid` to test this case.

3.  `WriteGear   ::  ERROR   :: BrokenPipeError caught, Wrong values passed to FFmpeg Pipe, Kindly Refer Docs!` , If "-resize" in output_params.

I have checked [this doc of WriteGear](https://abhitronix.github.io/vidgear/latest/gears/writegear/compression/params/).
There is no param named "-resize" both in FFmpeg Parameters and Special Internal Parameters.

So I removed `-resize` to test this case.

4. At last, the test case can run to finish. But the output video file can't be opened by video player and ffplay.

Looking forward to receiving your reply.  Thanks again.





### Terminal log output(Optional)

_No response_

### Python Code(Optional)

_No response_

### DeFFcode Version

0.2.3

### Python version

3.8.13

### Operating System version

Ubuntu 10.04

### Any other Relevant Information?

_No response_


Discussion / hints:


@seascheng Thanks for reporting this issue, I'll try address your issue by going over each problem you  encountered.

> Seems '-' is a wrong character in "–hwaccel", it should be "-", like "-vsync". They look very similar

@seascheng Yes, indeed it was a unicode error. I'll fix it.

> Con't use ffparams ("–hwaccel", "cuvid"). The ffmpeg command used by decoder at last is :
> 12:21:40 :: FFdecoder :: DEBUG :: Executing FFmpeg command: `ffmpeg -vsync 0 -hwaccel cuvid -vcodec h264_cuvid -i /data/sport/demo/deffcode_test/Big_Buck_Bunny_1080_10s_1MB.mp4 -pix_fmt bgr24 -s 1920x1080 -framerate 60.0 -f rawvideo -
> 
> But this will have an error:
> 
>   Impossible to convert between the formats supported by the filter 'Parsed_null_0' and the filter 'auto_scale_0'
> Error reinitializing filters!
> Failed to inject frame into filter network: Function not implemented
> I have checked commands:
> 
> ffmpeg -vsync 0 -vcodec hevc_cuvid -i /data/sport/auto_directed/ptz_camera/videos/guoxin_h265.mp4 -pix_fmt bgr24 -f rawvideo -
> 
> ffmpeg -vsync 0 -hwaccel_output_format cuda -hwaccel cuvid -vcodec hevc_cuvid -i /data/sport/auto_directed/ptz_camera/videos/guoxin_h265.mp4  -pix_fmt bgr24 -f rawvideo -

@seascheng You should not copy that example as it is, But rather you need to make changes according to your system's NVIDIA GPU. Therefore, to avoid using old CUVID decoder and directly use CUDA with NVDEC, and thereby let FFmpeg use best available encoder by default use following code instead. You can also leave frame format empty to use `RGB24` instead of `BGR24` with [WriteGear API `write()` method's `rgb_mode`](https://abhitronix.github.io/vidgear/latest/bonus/reference/writegear/#vidgear.gears.writegear.WriteGear.write):

```python
# import the necessary packages
from deffcode import FFdecoder
from vidgear.gears import WriteGear
import json

# define suitable FFmpeg parameter
ffparams = {
    "-vcodec": None,  # skip any decoder and let FFmpeg chose
    "-ffprefixes": [
        "-hwaccel",
        "nvdec",
        "-hwaccel_device",
        "0",
        "-hwaccel_output_format",
        "cuda",
    ],  # accelerator
}

# initialize and formulate the decoder with suitable source and params
decoder = FFdecoder("foo.mp4", verbose=True, **ffparams).formulate()

# retrieve framerate from source JSON Metadata and pass it as `-input_framerate`
# parameter for controlled framerate and define other parameters
output_params = {
    "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"],
    "-vcodec": "h264_nvenc",  # H.264 NVENC encoder
}

# Define writer with defined parameters and suitable
# output filename for e.g. `output_foo.mp4`
writer = WriteGear(output_filename="output_foo.mp4", **output_params)

# grab the BGR24 frame from the decoder
for frame in decoder.generateFrame():

    # check if frame is None
    if frame is None:
        break

    # {do something with the frame here}

    # writing RGB24 frame to writer
    writer.write(frame, rgb_mode=True)

# terminate the decoder
decoder.terminate()

# safely close writer
writer.close()
```

> So I removed -hwaccel cuvid to test this case.
> 
> WriteGear :: ERROR :: BrokenPipeError caught, Wrong values passed to FFmpeg Pipe, Kindly Refer Docs! , If "-resize" in output_params.
> I have checked [this doc of WriteGear](https://abhitronix.github.io/vidgear/latest/gears/writegear/compression/params/).
> There is no param named "-resize" both in FFmpeg Parameters and Special Internal Parameters.
> 
> So I removed -resize to test this case.

Yes, that parameter shouldn't be there, it was added just to resize frames directly inside GPU memory. Maybe it is not working, so it is best to remove that parameter.

 
@seascheng Kindly try above mentioned python code and paste full terminal log here directly. Goodluck!
@abhiTronix 
Thank you very much for your quick reply. 

full terminal log:
```
(yolo) cas-air@gpu-server:/data/sport/demo/deffcode_test$ python transcode_gpu_h264.py
15:41:05 ::    Utilies    ::   INFO   :: Running DeFFcode Version: 0.2.3
15:41:05 ::    Helper     ::   INFO   :: Running VidGear Version: 0.2.6
15:41:05 ::   FFhelper    ::  DEBUG   :: Final FFmpeg Path: ffmpeg
15:41:05 ::   FFhelper    ::  DEBUG   :: FFmpeg validity Test Passed!
15:41:05 ::   FFhelper    ::  DEBUG   :: Found valid FFmpeg Version: `b'N-107796-g1af7797d21'` installed on this system
15:41:05 ::    Sourcer    ::  DEBUG   :: Found valid FFmpeg executable: `ffmpeg`.
15:41:05 ::    Sourcer    ::  DEBUG   :: Retrieving Metadata...
15:41:05 ::   FFdecoder   :: CRITICAL :: Activating Video-Only Mode of Operation.
15:41:05 ::   FFdecoder   ::  DEBUG   :: Executing FFmpeg command: `ffmpeg -hwaccel nvdec -hwaccel_device 0 -hwaccel_output_format cuda -i /data/sport/demo/deffcode_test/Big_Buck_Bunny_1080_10s_1MB.mp4 -pix_fmt rgb24 -s 1920x1080 -framerate 60.0 -f rawvideo -`
ffmpeg version N-107796-g1af7797d21 Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 8 (Ubuntu 8.4.0-3ubuntu2)
  configuration: --enable-nonfree --enable-gpl --enable-libx264 --enable-cuda --enable-cuda-nvcc --enable-libx265 --enable-nvenc --enable-nvdec --enable-libnpp --extra-cflags=-I/usr/local/cuda/include --extra-ldflags=-L/usr/local/cuda/lib64
  libavutil      57. 33.101 / 57. 33.101
  libavcodec     59. 42.101 / 59. 42.101
  libavformat    59. 30.100 / 59. 30.100
  libavdevice    59.  8.101 / 59.  8.101
  libavfilter     8. 46.103 /  8. 46.103
  libswscale      6.  8.102 /  6.  8.102
  libswresample   4.  8.100 /  4.  8.100
  libpostproc    56.  7.100 / 56.  7.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/data/sport/demo/deffcode_test/Big_Buck_Bunny_1080_10s_1MB.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
  Duration: 00:00:10.00, start: 0.000000, bitrate: 837 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 832 kb/s, 60 fps, 60 tbr, 15360 tbn (default)
    Metadata:
      handler_name    : VideoHandler
      vendor_id       : [0][0][0][0]
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> rawvideo (native))
Press [q] to stop, [?] for help
Impossible to convert between the formats supported by the filter 'Parsed_null_0' and the filter 'auto_scale_0'
Error reinitializing filters!
Failed to inject frame into filter network: Function not implemented
Error while processing the decoded data for stream #0:0
Conversion failed!
15:41:06 ::   FFdecoder   ::  DEBUG   :: Terminating FFdecoder Pipeline...
15:41:06 ::   FFdecoder   ::  DEBUG   :: FFdecoder Pipeline terminated successfully
```

It looks the same as before
> It looks the same as before

@seascheng Thank you. for the logs. Yes but I think all these `-pix_fmt rgb24 -s 1920x1080 -framerate 60.0` parameters can be the problem as you can't change parameters within GPU memory(but only can apply filter with `-vf`) when `-hwaccel nvdec` is enabled. But can you test other pixel formats like `yuv444p` instead of both `rgb24/bgr24`?

> I have checked commands:
> 
> ffmpeg -vsync 0 -vcodec hevc_cuvid -i /data/sport/auto_directed/ptz_camera/videos/guoxin_h265.mp4 -pix_fmt bgr24 -f rawvideo -
> 
> ffmpeg -vsync 0 -hwaccel_output_format cuda -hwaccel cuvid -vcodec hevc_cuvid -i /data/sport/auto_directed/ptz_camera/videos/guoxin_h265.mp4  -pix_fmt bgr24 -f rawvideo -
> Both commands can be run. But -hwaccel cuvid and -pix_fmt bgr24 con't by used together.

Yeah you were right about `-hwaccel` and `-pix_fmt`  can't by used together: https://stackoverflow.com/a/5986748/10158117

> Internal hwaccel decoders are enabled via the -hwaccel option (not supported in ffplay). https://trac.ffmpeg.org/wiki/HWAccelIntro

I don't think we can explicity enable `-hwaccel` while decoding. Do you see any performance gain without `-hwaccel cuvid` in previous code?

Also, The problem is right now I don't have access to system with NVIDIA GPU, so I can't really test the best parameters to make this work, and I'm 100% sure it will work.  So you'll have to wait.
@abhiTronix 

I'm new at this.please point me out if I'm wrong
I have checked all params of this ffmpeg decode command

It seams `-hwaccel_output_format cuda`  and `-pix_fmt bgr24` should not be used together , on my env or server at least.

```
# failed: Impossible to convert between the formats supported by the filter 'Parsed_null_0' and the filter 'auto_scale_0'
$ ffmpeg -y -vsync 0 -hwaccel_output_format cuda -hwaccel cuda -c:v h264_cuvid -i input.mp4 -pix_fmt bgr24 -s 1280x720 -framerate 25.0 -f rawvideo /dev/null

# Success
$ ffmpeg -y -vsync 0  -hwaccel cuda -c:v h264_cuvid -i input.mp4 -pix_fmt bgr24 -s 1280x720 -framerate 25.0 -f rawvideo /dev/null
```
for `hwaccel_output_format`, in [NVIDIA FFmpeg Transcoding Guide](https://developer.nvidia.com/blog/nvidia-ffmpeg-transcoding-guide/)：
```
-hwaccel_output_format cuda	keeps the decoded frames in GPU memory
```
I don't know when the frame is processed in GPU or transferred  to  CPU and the relationship with ffmpeg params, If you have any references about this, I would be very grateful for them.

I tested decode performance on my server with Nvidia Tesla P4  
1. No `-hwaccel_output_format cuda -hwaccel cuda`, Just use CPU.
   `ffmpeg -y -vsync 0 -vcodec h264 -i input.mp4 -pix_fmt rgb24 -s 1280x720 -framerate 25.0 -f rawvideo /dev/null`


-   FFMPEG: frame= 5510 fps=992 q=-0.0 size=14874112kB time=00:03:40.76 bitrate=551951.1kbits/s speed=39.7x
-    CPU:  %CPU=2128,  %MEM=0.7
-    GPU:   0%

2. with` -hwaccel cuda` , no `-hwaccel_output_format cuda`
`ffmpeg -y -vsync 0 -hwaccel cuda -c:v h264_cuvid -i input.mp4 -pix_fmt bgr24 -s 1280x720 -framerate 25.0 -f rawvideo /dev/null`

-   FFMPEG: frame=11138 fps=717 q=-0.0 size=30069760kB time=00:07:25.60 bitrate=552808.5kbits/s speed=28.7x
-    CPU:  %CPU=1486,  %MEM=0.7
-    GPU:  Memory-Usage=270M,  GPU-Util=24%

3. With `-hwaccel_output_format cuda -hwaccel cuda`,  and  `-vf`
`ffmpeg -y -vsync 0 -hwaccel_output_format cuda -hwaccel cuda -c:v h264_cuvid -i input.mp4 -vf "scale_npp=format=yuv420p,hwdownload,format=yuv420p,fps=25.0" -f rawvideo /dev/null`

-   FFMPEG: frame=42794 fps=949 q=-0.0 size=57770496kB time=00:28:31.84 bitrate=276460.4kbits/s speed=  38x
-    CPU:  %CPU=170.5,  %MEM=0.7
-    GPU:  Memory-Usage=270M,  GPU-Util=29%


Yes, using pure CPU and using pure GPU almost have same performance, but using pure CPU, the CPU useage is too high, especially in a server with other services running.

My ideal is to do all steps (decode to frame, frame process, and encoded to video ）in one GPU(my server has 8 GPU cards), so i search solution and find this project.  Thanks for your work on this.

At last I use this ffparams:
```
# define suitable FFmpeg parameter
ffparams = {
    "-vcodec": "h264_cuvid",
    "-ffprefixes": [
        "-hwaccel",
        "nvdec",
        "-hwaccel_device",
        "0",
    ],  # accelerator
}
```

In for `frame in decoder.generateFrame()`, I use `cv2.imwrite("images/image-{:0>5d}.jpg".format(i),frame)` to save all frames(bgr24) succesfully, but after using WriteGear encode all frames to a video, as mentioned before, the video con't play.

This is my first touch WriteGear, I will take a look what happened in WriteGear and what is the difference with ffmpeg pip




> I tested decode performance on my server with Nvidia Tesla P4
> 
> No -hwaccel_output_format cuda -hwaccel cuda, Just use CPU.
> ffmpeg -y -vsync 0 -vcodec h264 -i input.mp4 -pix_fmt rgb24 -s 1280x720 -framerate 25.0 -f rawvideo /dev/null
> FFMPEG: frame= 5510 fps=992 q=-0.0 size=14874112kB time=00:03:40.76 bitrate=551951.1kbits/s speed=39.7x
> CPU: %CPU=2128, %MEM=0.7
> GPU: 0%
> with -hwaccel cuda , no -hwaccel_output_format cuda
> ffmpeg -y -vsync 0 -hwaccel cuda -c:v h264_cuvid -i input.mp4 -pix_fmt bgr24 -s 1280x720 -framerate 25.0 -f rawvideo /dev/null
> FFMPEG: frame=11138 fps=717 q=-0.0 size=30069760kB time=00:07:25.60 bitrate=552808.5kbits/s speed=28.7x
> CPU: %CPU=1486, %MEM=0.7
> GPU: Memory-Usage=270M, GPU-Util=24%
> With -hwaccel_output_format cuda -hwaccel cuda, and -vf
> ffmpeg -y -vsync 0 -hwaccel_output_format cuda -hwaccel cuda -c:v h264_cuvid -i input.mp4 -vf "scale_npp=format=yuv420p,hwdownload,format=yuv420p,fps=25.0" -f rawvideo /dev/null
> FFMPEG: frame=42794 fps=949 q=-0.0 size=57770496kB time=00:28:31.84 bitrate=276460.4kbits/s speed= 38x
> CPU: %CPU=170.5, %MEM=0.7
> GPU: Memory-Usage=270M, GPU-Util=29%
> Yes, using pure CPU and using pure GPU almost have same performance, but using pure CPU, the CPU useage is too high, especially in a server with other services running.
> 
> My ideal is to do all steps (decode to frame, frame process, and encoded to video ）in one GPU(my server has 8 GPU cards), so i search solution and find this project. Thanks for your work on this.
> 
> At last I use this ffparams:
> 
> # define suitable FFmpeg parameter
> ffparams = {
>     "-vcodec": "h264_cuvid",
>     "-ffprefixes": [
>         "-hwaccel",
>         "nvdec",
>         "-hwaccel_device",
>         "0",
>     ],  # accelerator
> }
> 

@seascheng Thank you for this elaborated insight, This just what I needed. I just modified DeFFcode code to drop all three `-pix_fmt`, `-s` and `-framerate` parameter directly from FFdecoder API, so you can test commands like `ffmpeg -y -vsync 0 -hwaccel_output_format cuda -hwaccel cuda -c:v h264_cuvid -i input.mp4 -vf "scale_npp=format=yuv420p,hwdownload,format=yuv420p,fps=25.0" -f rawvideo -` directly in FFdecoder. Please wait for my next PR and following comments for python code and instructions.

> I don't know when the frame is processed in GPU or transferred to CPU and the relationship with ffmpeg params, If you have any references about this, I would be very grateful for them.

See this: https://developer.nvidia.com/blog/nvidia-ffmpeg-transcoding-guide/

> In for frame in decoder.generateFrame(), I use cv2.imwrite("images/image-{:0>5d}.jpg".format(i),frame) to save all frames(bgr24) succesfully, but after using WriteGear encode all frames to a video, as mentioned before, the video con't play.

What Video Player are you using to play video file? for e.g vlc. mpv, wmp etc.
@seascheng I've successfully done the coding part to use filters(like `fps`, `format`, `scale`) instead of parameters(such as `-framerate`, `-pix_fmt`, `-size`). Please wait for my next commits/PR and following comments for python code and instructions.

Fix patch:
diff --git a/README.md b/README.md
index e2cd49f..4bb5614 100644
--- a/README.md
+++ b/README.md
@@ -359,7 +359,7 @@ Internal URLs
 [release]:https://github.com/abhiTronix/deffcode/releases/latest
 [recipes]:https://abhitronix.github.io/deffcode/latest/recipes/basic/
 [license]:https://github.com/abhiTronix/deffcode/blob/master/LICENSE
-[help]:https://abhitronix.github.io/deffcode/latest/https://abhitronix.github.io/deffcode/latest/help/get_help
+[help]:https://abhitronix.github.io/deffcode/latest/help/get_help
 [installation-notes]:https://abhitronix.github.io/deffcode/latest/installation/#installation-notes
 [ffdecoder-api]:https://abhitronix.github.io/deffcode/latest/reference/ffdecoder/#ffdecoder-api
 [sourcer-api]:https://abhitronix.github.io/deffcode/latest/reference/sourcer/#sourcer-api
diff --git a/deffcode/ffdecoder.py b/deffcode/ffdecoder.py
index 0e708ea..6ea76ce 100644
--- a/deffcode/ffdecoder.py
+++ b/deffcode/ffdecoder.py
@@ -100,7 +100,7 @@ def __init__(
 
         # define frame pixel-format for decoded frames
         self.__frame_format = (
-            frame_format.strip() if isinstance(frame_format, str) else None
+            frame_format.lower().strip() if isinstance(frame_format, str) else None
         )
 
         # handles user-defined parameters
@@ -143,6 +143,22 @@ def __init__(
         # reset improper values
         sourcer_params = {} if not isinstance(sourcer_params, dict) else sourcer_params
 
+        # handle user ffmpeg pre-headers(parameters such as `-re`) parameters (must be a list)
+        self.__ffmpeg_prefixes = self.__extra_params.pop("-ffprefixes", [])
+        # check if not valid type
+        if not isinstance(self.__ffmpeg_prefixes, list):
+            # log it
+            logger.warning(
+                "Discarding invalid `-ffprefixes` value of wrong type: `{}`!".format(
+                    type(self.__ffmpeg_prefixes).__name__
+                )
+            )
+            # reset improper values
+            self.__ffmpeg_prefixes = []
+        else:
+            # also pass valid ffmpeg pre-headers to Sourcer API
+            sourcer_params["-ffprefixes"] = self.__ffmpeg_prefixes
+
         # pass parameter(if specified) to Sourcer API, specifying where to save the downloaded FFmpeg Static
         # assets on Windows(if specified)
         sourcer_params["-ffmpeg_download_path"] = self.__extra_params.pop(
@@ -160,10 +176,15 @@ def __init__(
             else default_stream_indexes
         )
 
+        # pass FFmpeg filter to Sourcer API params for processing
+        if set(["-vf", "-filter_complex"]).intersection(self.__extra_params.keys()):
+            key = "-vf" if "-vf" in self.__extra_params else "-filter_complex"
+            sourcer_params[key] = self.__extra_params[key]
+
         # define dict to store user-defined parameters
         self.__user_metadata = {}
         # extract and assign source metadata as dict
-        self.__source_metadata = (
+        (self.__sourcer_metadata, self.__missing_prop) = (
             Sourcer(
                 source=source,
                 source_demuxer=source_demuxer,
@@ -172,13 +193,11 @@ def __init__(
                 **sourcer_params
             )
             .probe_stream(default_stream_indexes=default_stream_indexes)
-            .retrieve_metadata()
+            .retrieve_metadata(force_retrieve_missing=True)
         )
-        # add dummy value for `output_frames_pixfmt` source metadata
-        self.__source_metadata["output_frames_pixfmt"] = "unknown"
 
         # handle valid FFmpeg assets location
-        self.__ffmpeg = self.__source_metadata["ffmpeg_binary_path"]
+        self.__ffmpeg = self.__sourcer_metadata["ffmpeg_binary_path"]
 
         # handle pass-through audio mode works in conjunction with WriteGear [TODO]
         self.__passthrough_mode = self.__extra_params.pop("-passthrough_audio", False)
@@ -186,20 +205,20 @@ def __init__(
             self.__passthrough_mode = False
 
         # handle mode of operation
-        if self.__source_metadata["source_has_image_sequence"]:
+        if self.__sourcer_metadata["source_has_image_sequence"]:
             # image-sequence mode
             self.__opmode = "imgseq"
         elif (
-            self.__source_metadata[
+            self.__sourcer_metadata[
                 "source_has_video"
             ]  # audio is only for pass-through, not really for audio decoding yet.
-            and self.__source_metadata["source_has_audio"]
+            and self.__sourcer_metadata["source_has_audio"]
             and self.__passthrough_mode  # [TODO]
         ):
             self.__opmode = "av"
-        # elif __defop_mode == "ao" and self.__source_metadata.contains_audio: # [TODO]
+        # elif __defop_mode == "ao" and self.__sourcer_metadata.contains_audio: # [TODO]
         #    self.__opmode = "ao"
-        elif self.__source_metadata["source_has_video"]:
+        elif self.__sourcer_metadata["source_has_video"]:
             # video-only mode
             self.__opmode = "vo"
         else:
@@ -208,23 +227,23 @@ def __init__(
                 "Unable to find any usable video stream in the given source!"
             )
         # store as metadata
-        self.__source_metadata["ffdecoder_operational_mode"] = self.__supported_opmodes[
+        self.__missing_prop["ffdecoder_operational_mode"] = self.__supported_opmodes[
             self.__opmode
         ]
-        # and log it
-        self.__verbose_logs and logger.critical(
-            "Activating {} Mode of Operation.".format(
-                self.__supported_opmodes[self.__opmode]
-            )
-        )
 
-        # handle user-defined framerate
-        __framerate = self.__extra_params.pop("-framerate", 0.0)
-        if not (__framerate is None) and isinstance(__framerate, (float, int)):
+        # handle user-defined output framerate
+        __framerate = self.__extra_params.pop("-framerate", None)
+        if (
+            isinstance(__framerate, str)
+            and __framerate
+            == "null"  # special mode to discard `-framerate/-r` parameter
+        ):
+            self.__inputframerate = __framerate
+        elif isinstance(__framerate, (float, int)):
             self.__inputframerate = float(__framerate) if __framerate > 0.0 else 0.0
         else:
             # warn if wrong type
-            logger.warning(
+            not (__framerate is None) and logger.warning(
                 "Discarding invalid `-framerate` value of wrong type `{}`!".format(
                     type(__framerate).__name__
                 )
@@ -232,19 +251,26 @@ def __init__(
             # reset to default
             self.__inputframerate = 0.0
 
-        # FFmpeg parameter `-s` is unsupported
-        if not (self.__extra_params.pop("-s", None) is None):
-            logger.warning(
-                "Discarding user-defined `-s` FFmpeg parameter as it can only be assigned with `-custom_resolution` attribute! Read docs for more details."
-            )
-        # handle user defined decoded frame resolution(must be a tuple or list)
+        # handle user defined decoded frame resolution
         self.__custom_resolution = self.__extra_params.pop("-custom_resolution", None)
-        if not (self.__custom_resolution is None) and (
-            not isinstance(self.__custom_resolution, (list, tuple))
-            or len(self.__custom_resolution) != 2
+        if (
+            isinstance(self.__custom_resolution, str)
+            and self.__custom_resolution
+            == "null"  # special mode to discard `-size/-s` parameter
+        ) or (
+            isinstance(self.__custom_resolution, (list, tuple))
+            and len(self.__custom_resolution)
+            == 2  # valid resolution(must be a tuple or list)
         ):
             # log it
-            logger.warning(
+            self.__verbose_logs and not isinstance(
+                self.__custom_resolution, str
+            ) and logger.debug(
+                "Setting raw frames size: `{}`.".format(self.__custom_resolution)
+            )
+        else:
+            # log it
+            not (self.__custom_resolution is None) and logger.warning(
                 "Discarding invalid `-custom_resolution` value: `{}`!".format(
                     self.__custom_resolution
                 )
@@ -252,18 +278,6 @@ def __init__(
             # reset improper values
             self.__custom_resolution = None
 
-        # handle user defined ffmpeg pre-headers(parameters such as `-re`) parameters (must be a list)
-        self.__ffmpeg_prefixes = self.__extra_params.pop("-ffprefixes", [])
-        if not isinstance(self.__ffmpeg_prefixes, list):
-            # log it
-            logger.warning(
-                "Discarding invalid `-ffprefixes` value of wrong type: `{}`!".format(
-                    type(self.__ffmpeg_prefixes).__name__
-                )
-            )
-            # reset improper values
-            self.__ffmpeg_prefixes = []
-
     def formulate(self):
 
         """
@@ -280,8 +294,9 @@ def formulate(self):
             # dynamically pre-assign a default video-decoder (if not assigned by user).
             supported_vdecodecs = get_supported_vdecoders(self.__ffmpeg)
             default_vdecodec = (
-                self.__source_metadata["source_video_decoder"]
-                if self.__source_metadata["source_video_decoder"] in supported_vdecodecs
+                self.__sourcer_metadata["source_video_decoder"]
+                if self.__sourcer_metadata["source_video_decoder"]
+                in supported_vdecodecs
                 else "unknown"
             )
             if "-c:v" in self.__extra_params:
@@ -336,113 +351,235 @@ def formulate(self):
                     output_params["-frames:v"] = value
 
             # dynamically calculate default raw-frames pixel format(if not assigned by user).
+            # notify FFmpeg `-pix_fmt` parameter cannot be assigned directly
+            if "-pix_fmt" in self.__extra_params:
+                logger.warning(
+                    "Discarding user-defined `-pix_fmt` value as it can only be assigned with `frame_format` parameter!"
+                )
+                self.__extra_params.pop("-pix_fmt", None)
+            # get supported FFmpeg pixfmt data with depth and bpp(bits-per-pixel)
             self.__ff_pixfmt_metadata = get_supported_pixfmts(self.__ffmpeg)
             supported_pixfmts = [fmts[0] for fmts in self.__ff_pixfmt_metadata]
+
+            # calculate default pixel-format
+            # Check special case  - `frame_format`(or `-pix_fmt`) parameter discarded from pipeline
+            self.__frame_format == "null" and logger.critical(
+                "Manually discarding `frame_format`(or `-pix_fmt`) parameter from this pipeline."
+            )
+            # choose between rgb24(if available) or source pixel-format
+            # otherwise, only source pixel-format for special case
             default_pixfmt = (
                 "rgb24"
-                if "rgb24" in supported_pixfmts
-                else self.__source_metadata["source_video_pixfmt"]
+                if "rgb24" in supported_pixfmts and self.__frame_format != "null"
+                else self.__sourcer_metadata["source_video_pixfmt"]
             )
-            # assigning `-pix_fmt` parameter cannot be assigned directly
-            if "-pix_fmt" in self.__extra_params:
-                logger.warning(
-                    "Discarding user-defined `-pix_fmt` value as it can only be assigned with `frame_format` parameter! Read docs for more details."
-                )
-                self.__extra_params.pop("-pix_fmt", None)
             # assign output raw-frames pixel format
+            rawframe_pixfmt = None
             if (
-                "output_frames_pixfmt" in self.__source_metadata
-                and self.__source_metadata["output_frames_pixfmt"] in supported_pixfmts
-            ):
-                # check if manually defined via `metadata` property object
-                # assign if valid and supported
-                output_params["-pix_fmt"] = self.__source_metadata[
-                    "output_frames_pixfmt"
-                ].strip()
-            elif (
                 not (self.__frame_format is None)
                 and self.__frame_format in supported_pixfmts
             ):
-                # check if assigned via `frame_format` parameter
+                # check if valid and supported `frame_format` parameter assigned
+                rawframe_pixfmt = self.__frame_format.strip()
+                self.__verbose_logs and logger.info(
+                    "User-defined `{}` frame pixel-format will be used for this pipeline.".format(
+                        rawframe_pixfmt
+                    )
+                )
+            elif (
+                "output_frames_pixfmt"
+                in self.__sourcer_metadata  # means `format` filter is defined
+                and self.__sourcer_metadata["output_frames_pixfmt"] in supported_pixfmts
+            ):
                 # assign if valid and supported
-                output_params["-pix_fmt"] = self.__frame_format.strip()
+                rawframe_pixfmt = self.__sourcer_metadata[
+                    "output_frames_pixfmt"
+                ].strip()
+                self.__verbose_logs and logger.info(
+                    "FFmpeg filter values will be used for this pipeline for defining output pixel-format."
+                )
             else:
                 # reset to default if not supported
-                not (self.__frame_format is None) and logger.critical(
-                    "Provided FFmpeg does not support `{}` pixel format(pix_fmt). Switching to default `{}`!".format(
-                        self.__frame_format, "rgb24"
+                rawframe_pixfmt = default_pixfmt
+                # log it accordingly
+                if self.__frame_format is None:
+                    logger.info(
+                        "Using default `{}` pixel-format for this pipeline.".format(
+                            default_pixfmt
+                        )
+                    )
+                else:
+                    logger.warning(
+                        "{} Switching to default `{}` pixel-format!".format(
+                            "Provided FFmpeg does not supports `{}` pixel-format.".format(
+                                self.__sourcer_metadata["output_frames_pixfmt"]
+                                if "output_frames_pixfmt" in self.__sourcer_metadata
+                                else self.__frame_format
+                            )
+                            if self.__frame_format != "null"
+                            else "No usable pixel-format defined.",
+                            default_pixfmt,
+                        )
                     )
-                )
-                output_params["-pix_fmt"] = default_pixfmt
 
-            # dynamically calculate raw-frame dtype based on pix format selected
-            frames_pixfmt = output_params["-pix_fmt"]
+            # dynamically calculate raw-frame datatype based on pixel-format selected
             (self.__raw_frame_depth, rawframesbpp) = [
                 (int(x[1]), int(x[2]))
                 for x in self.__ff_pixfmt_metadata
-                if x[0] == frames_pixfmt
+                if x[0] == rawframe_pixfmt
             ][0]
             raw_bit_per_component = rawframesbpp // self.__raw_frame_depth
-            if raw_bit_per_component in [4, 8]:
+            if 4 <= raw_bit_per_component <= 8:
                 self.__raw_frame_dtype = np.dtype("u1")
-            elif raw_bit_per_component == 16:
-                if frames_pixfmt.endswith("le"):
+            elif 8 < raw_bit_per_component <= 16 and rawframe_pixfmt.endswith(
+                ("le", "be")
+            ):
+                if rawframe_pixfmt.endswith("le"):
                     self.__raw_frame_dtype = np.dtype("<u2")
-                elif frames_pixfmt.endswith("be"):
-                    self.__raw_frame_dtype = np.dtype(">u2")
                 else:
-                    pass
+                    self.__raw_frame_dtype = np.dtype(">u2")
             else:
-                # reset to default if not supported
-                logger.critical(
-                    "Given `frame_format` value: {} is not supported by FFdecoder. Switching to default `{}`!".format(
-                        frames_pixfmt, "rgb24"
+                # reset to both pixel-format and datatype to default if not supported
+                not (self.__frame_format is None) and logger.warning(
+                    "Selected pixel-format `{}` dtype is not supported by FFdecoder API. Switching to default `rgb24` pixel-format!".format(
+                        rawframe_pixfmt
                     )
                 )
-                output_params["-pix_fmt"] = default_pixfmt
-                # change dtype
+                rawframe_pixfmt = "rgb24"
                 self.__raw_frame_dtype = np.dtype("u1")
-            # assign to global parameter
-            self.__raw_frame_pixfmt = output_params["-pix_fmt"]
-            # also store as metadata
-            self.__source_metadata["output_frames_pixfmt"] = output_params["-pix_fmt"]
-
-            # handle raw-frame size
-            if not (self.__custom_resolution is None):
-                # assign if assigned by user
+
+            # Check if not special case
+            if self.__frame_format != "null":
+                # assign to FFmpeg pipeline otherwise
+                output_params["-pix_fmt"] = rawframe_pixfmt
+            # assign to global parameter further usage
+            self.__raw_frame_pixfmt = rawframe_pixfmt
+            # also override as metadata(if available)
+            if "output_frames_pixfmt" in self.__sourcer_metadata:
+                self.__sourcer_metadata[
+                    "output_frames_pixfmt"
+                ] = self.__raw_frame_pixfmt
+
+            # handle raw-frame resolution
+            # notify FFmpeg `-s` parameter cannot be assigned directly
+            if "-s" in self.__extra_params:
+                logger.warning(
+                    "Discarding user-defined `-s` FFmpeg parameter as it can only be assigned with `-custom_resolution` attribute! Read docs for more details."
+                )
+                self.__extra_params.pop("-s", None)
+            # assign output rawframe resolution
+            if not (self.__custom_resolution is None) and not isinstance(
+                self.__custom_resolution, str
+            ):
+                # assign if assigned by user and not "null"(str)
                 self.__raw_frame_resolution = self.__custom_resolution
+                self.__verbose_logs and logger.info(
+                    "User-defined `{}` frame resolution will be used for this pipeline.".format(
+                        self.__raw_frame_resolution
+                    )
+                )
             elif (
-                self.__source_metadata["source_video_resolution"]
-                and len(self.__source_metadata["source_video_resolution"]) == 2
+                "output_frames_resolution"
+                in self.__sourcer_metadata  # means `scale` filter is defined
+                and self.__sourcer_metadata["output_frames_resolution"]
+                and len(self.__sourcer_metadata["output_frames_resolution"]) == 2
             ):
-                # calculate raw-frame resolution/dimensions based on source (if not assigned by user).
-                self.__raw_frame_resolution = self.__source_metadata[
+                # calculate raw-frame resolution/dimensions based on output.
+                self.__raw_frame_resolution = self.__sourcer_metadata[
+                    "output_frames_resolution"
+                ]
+            elif (
+                self.__sourcer_metadata["source_video_resolution"]
+                and len(self.__sourcer_metadata["source_video_resolution"]) == 2
+            ):
+                # calculate raw-frame resolution/dimensions based on source.
+                self.__raw_frame_resolution = self.__sourcer_metadata[
                     "source_video_resolution"
                 ]
             else:
                 # otherwise raise error
                 raise RuntimeError(
-                    "Invalid `source_video_resolution` metadata value detected!"
+                    "Both source and output metadata values found Invalid with {} `-custom_resolution` attribute. Aborting!".format(
+                        "null"
+                        if isinstance(self.__inputframerate, str)
+                        else "undefined"
+                    )
+                )
+            # special mode to discard `-size/-s` FFmpeg parameter completely
+            if isinstance(self.__custom_resolution, str):
+                logger.critical(
+                    "Manually discarding `-size/-s` FFmpeg parameter from this pipeline."
+                )
+            else:
+                # add to pipeline
+                dimensions = "{}x{}".format(
+                    self.__raw_frame_resolution[0], self.__raw_frame_resolution[1]
+                )
+                output_params["-s"] = str(dimensions)
+            # log if filters or default source is used
+            self.__verbose_logs and (
+                self.__custom_resolution is None
+                or isinstance(self.__custom_resolution, str)
+            ) and logger.info(
+                "{} for this pipeline for defining output resolution.".format(
+                    "FFmpeg filter values will be used"
+                    if "output_frames_resolution" in self.__sourcer_metadata
+                    else "Default source resolution will be used"
                 )
-            # add to pipeline
-            dimensions = "{}x{}".format(
-                self.__raw_frame_resolution[0], self.__raw_frame_resolution[1]
             )
-            output_params["-s"] = str(dimensions)
 
             # dynamically calculate raw-frame framerate based on source (if not assigned by user).
-            if self.__inputframerate > 0.0:
-                # assign if assigned by user
+            if (
+                not isinstance(self.__inputframerate, str)
+                and self.__inputframerate > 0.0
+            ):
+                # assign if assigned by user and not "null"(str)
                 output_params["-framerate"] = str(self.__inputframerate)
-            elif self.__source_metadata["source_video_framerate"] > 0.0:
-                # calculate raw-frame framerate based on source
-                output_params["-framerate"] = str(
-                    self.__source_metadata["source_video_framerate"]
+                self.__verbose_logs and logger.info(
+                    "User-defined `{}` output framerate will be used for this pipeline.".format(
+                        str(self.__inputframerate)
+                    )
+                )
+            elif (
+                "output_framerate"
+                in self.__sourcer_metadata  # means `fps` filter is defined
+                and self.__sourcer_metadata["output_framerate"] > 0.0
+            ):
+                # special mode to discard `-framerate/-r` FFmpeg parameter completely
+                if self.__inputframerate == "null":
+                    logger.critical(
+                        "Manually discarding `-framerate/-r` FFmpeg parameter from this pipeline."
+                    )
+                else:
+                    # calculate raw-frame framerate based on output
+                    output_params["-framerate"] = str(
+                        self.__sourcer_metadata["output_framerate"]
+                    )
+                self.__verbose_logs and logger.info(
+                    "FFmpeg filter values will be used for this pipeline for defining output framerate."
+                )
+            elif self.__sourcer_metadata["source_video_framerate"] > 0.0:
+                # special mode to discard `-framerate/-r` FFmpeg parameter completely
+                if self.__inputframerate == "null":
+                    logger.critical(
+                        "Manually disabling `-framerate/-r` FFmpeg parameter for this pipeline."
+                    )
+                else:
+                    # calculate raw-frame framerate based on source
+                    output_params["-framerate"] = str(
+                        self.__sourcer_metadata["source_video_framerate"]
+                    )
+                self.__verbose_logs and logger.info(
+                    "Default source framerate will be used for this pipeline for defining output framerate."
                 )
             else:
                 # otherwise raise error
                 raise RuntimeError(
-                    "Invalid `source_video_framerate` metadata value detected!"
+                    "Both source and output metadata values found Invalid with {} `-framerate` attribute. Aborting!".format(
+                        "null"
+                        if isinstance(self.__inputframerate, str)
+                        else "undefined"
+                    )
                 )
 
             # add rest to output parameters
@@ -452,8 +589,8 @@ def formulate(self):
             # TODO Added support for `-re -stream_loop` and `-loop`
             if "-frames:v" in input_params:
                 self.__raw_frame_num = input_params["-frames:v"]
-            elif self.__source_metadata["approx_video_nframes"]:
-                self.__raw_frame_num = self.__source_metadata["approx_video_nframes"]
+            elif self.__sourcer_metadata["approx_video_nframes"] > 0:
+                self.__raw_frame_num = self.__sourcer_metadata["approx_video_nframes"]
             else:
                 self.__raw_frame_num = None
                 # log that number of frames are unknown
@@ -461,6 +598,13 @@ def formulate(self):
                     "Live/Network Stream detected! Number of frames in given source are not known."
                 )
 
+            # log Mode of Operation
+            self.__verbose_logs and logger.critical(
+                "Activating {} Mode of Operation.".format(
+                    self.__supported_opmodes[self.__opmode]
+                )
+            )
+
             # compose the Pipeline using formulated FFmpeg parameters
             self.__launch_FFdecoderline(input_params, output_params)
 
@@ -496,7 +640,7 @@ def __fetchNextfromPipeline(self):
                 dtype=self.__raw_frame_dtype,
             )
         except Exception as e:
-            raise RuntimeError("Frame fetching failed with error: {}".format(str(e)))
+            raise RuntimeError("Frame buffering failed with error: {}".format(str(e)))
         return (
             nparray
             if not (nparray is None) and len(nparray) == raw_frame_size
@@ -521,15 +665,6 @@ def __fetchNextFrame(self):
                     self.__raw_frame_depth,
                 )
             )[:, :, 0]
-        elif self.__raw_frame_pixfmt == "yuv444p":
-            # reconstruct exclusive `yuv444p` frames
-            frame = frame.reshape(
-                (
-                    self.__raw_frame_depth,
-                    self.__raw_frame_resolution[1],
-                    self.__raw_frame_resolution[0],
-                )
-            ).transpose((1, 2, 0))
         else:
             # reconstruct default frames
             frame = frame.reshape(
@@ -586,8 +721,15 @@ def metadata(self):
         # import dependency
         import json
 
-        # return complete (source+user-defined) metadata as JSON string
-        return json.dumps({**self.__source_metadata, **self.__user_metadata}, indent=2)
+        # return complete metadata information as JSON string
+        return json.dumps(
+            {
+                **self.__sourcer_metadata,  # source video
+                **self.__missing_prop,  # missing properties
+                **self.__user_metadata,  # user-defined
+            },
+            indent=2,
+        )
 
     @metadata.setter
     def metadata(self, value):
@@ -601,24 +743,61 @@ def metadata(self, value):
         if value and isinstance(value, dict):
             # log it
             self.__verbose_logs and logger.info("Updating Metadata...")
-            # extract any source metadata keys
-            default_keys = set(value).intersection(self.__source_metadata)
+            # extract any source and output internal metadata keys
+            default_keys = set(value).intersection(
+                {**self.__sourcer_metadata, **self.__missing_prop}
+            )
+            # counterpart source properties for each output properties
+            counterpart_prop = {
+                "output_frames_resolution": "source_video_resolution",
+                "output_frames_pixfmt": "source_video_pixfmt",
+                "output_framerate": "source_video_framerate",
+            }
             # iterate over source metadata keys and sanitize it
             for key in default_keys or []:
                 if key == "source":
-                    # `source` metadata value cannot be altered
+                    # metadata properties that cannot be altered
                     logger.warning(
-                        "`source` metadata value cannot be altered. Discarding!"
+                        "`{}` metadata property value cannot be altered. Discarding!".format(
+                            key
+                        )
                     )
-                elif isinstance(value[key], type(self.__source_metadata[key])):
+                elif key in self.__missing_prop:
+                    # missing metadata properties are unavailable and read-only
+                    # notify user about alternative counterpart property (if available)
+                    logger.warning(
+                        "`{}` metadata property is read-only".format(key)
+                        + (
+                            ". Try updating `{}` property instead!".format(
+                                counterpart_prop[key]
+                            )
+                            if key in counterpart_prop.keys()
+                            else " and cannot be updated!"
+                        )
+                    )
+                elif isinstance(value[key], type(self.__sourcer_metadata[key])):
                     # check if correct datatype as original
+                    self.__verbose_logs and logger.info(
+                        "Updating `{}`{} metadata property to `{}`.".format(
+                            key,
+                            " and its counterpart"
+                            if key in counterpart_prop.values()
+                            else "",
+                            value[key],
+                        )
+                    )
                     # update source metadata if valid
-                    self.__source_metadata.update(value)
-                    continue
+                    self.__sourcer_metadata[key] = value[key]
+                    # also update missing counterpart property (if available)
+                    counter_key = next(
+                        (k for k, v in counterpart_prop.items() if v == key), ""
+                    )
+                    if counter_key:
+                        self.__missing_prop[counter_key] = value[key]
                 else:
                     # otherwise discard and log it
                     logger.warning(
-                        "Manually assigned `{}` metadata value is invalid type. Discarding!"
+                        "Manually assigned `{}` metadata property value is of invalid type. Discarding!"
                     ).format(key)
                 # delete invalid key
                 del value[key]
@@ -626,7 +805,7 @@ def metadata(self, value):
             # Python's `json` module converts Python tuples to JSON lists
             # because that's the closest thing in JSON to a tuple.
             any(isinstance(value[x], tuple) for x in value) and logger.warning(
-                "All TUPLE metadata values will be converted to LIST datatype. Read docs for more details."
+                "All TUPLE metadata properties will be converted to LIST datatype. Read docs for more details."
             )
             # update user-defined metadata
             self.__user_metadata.update(value)
@@ -656,19 +835,17 @@ def __launch_FFdecoderline(self, input_params, output_params):
             + self.__ffmpeg_prefixes
             + input_parameters
             + (
-                ["-f", self.__source_metadata["source_demuxer"]]
-                if ("source_demuxer" in self.__source_metadata.keys())
+                ["-f", self.__sourcer_metadata["source_demuxer"]]
+                if ("source_demuxer" in self.__sourcer_metadata.keys())
                 else []
             )
-            + ["-i", self.__source_metadata["source"]]
+            + ["-i", self.__sourcer_metadata["source"]]
             + output_parameters
             + ["-f", "rawvideo", "-"]
         )
-        # assign value to class variable
-        _cmd = " ".join(cmd)
         # compose the FFmpeg process
         if self.__verbose_logs:
-            logger.debug("Executing FFmpeg command: `{}`".format(_cmd))
+            logger.debug("Executing FFmpeg command: `{}`".format(" ".join(cmd)))
             # In debugging mode
             self.__process = sp.Popen(
                 cmd, stdin=sp.DEVNULL, stdout=sp.PIPE, stderr=None
@@ -689,18 +866,18 @@ def terminate(self):
         self.__terminate_stream = True
         # check if no process was initiated at first place
         if self.__process is None or not (self.__process.poll() is None):
-            logger.info("Pipeline already terminated!")
+            logger.info("Pipeline already terminated.")
             return
         # Attempt to close pipeline.
         # close `stdin` output
         self.__process.stdin and self.__process.stdin.close()
         # close `stdout` output
         self.__process.stdout and self.__process.stdout.close()
-        # wait if still process is still processing some information
+        # terminate/kill process if still processing
         if self.__process.poll() is None:
+            # demuxers prefer kill
             self.__process.kill()
+        # wait if not exiting
         self.__process.wait()
         self.__process = None
-        self.__verbose_logs and logger.debug(
-            "FFdecoder Pipeline terminated successfully"
-        )
+        logger.info("Pipeline terminated successfully.")
diff --git a/deffcode/sourcer.py b/deffcode/sourcer.py
index 08c255b..8aff47d 100644
--- a/deffcode/sourcer.py
+++ b/deffcode/sourcer.py
@@ -28,7 +28,7 @@
 import numpy as np
 
 # import utils packages
-from .utils import logger_handler, validate_device_index
+from .utils import logger_handler, validate_device_index, dict2Args
 from .ffhelper import (
     check_sp_output,
     get_supported_demuxers,
@@ -101,7 +101,7 @@ def __init__(
         # sanitize sourcer_params
         self.__sourcer_params = {
             str(k).strip(): str(v).strip()
-            if not isinstance(v, (dict, list, int, float))
+            if not isinstance(v, (dict, list, int, float, tuple))
             else v
             for k, v in sourcer_params.items()
         }
@@ -189,7 +189,7 @@ def __init__(
         # handles source stream
         self.__source = source
 
-        # create shallow copy for further usage #TODO
+        # creates shallow copy for further usage #TODO
         self.__source_org = copy.copy(self.__source)
         self.__source_demuxer_org = copy.copy(self.__source_demuxer)
 
@@ -198,22 +198,28 @@ def __init__(
         self.__extracted_devices_list = []
 
         # various source stream params
-        self.__default_video_resolution = ""  # handle stream resolution
-        self.__default_video_framerate = ""  # handle stream framerate
-        self.__default_video_bitrate = ""  # handle stream's video bitrate
-        self.__default_video_pixfmt = ""  # handle stream's video pixfmt
-        self.__default_video_decoder = ""  # handle stream's video decoder
-        self.__default_source_duration = ""  # handle stream's video duration
-        self.__approx_video_nframes = ""  # handle approx stream frame number
-        self.__default_audio_bitrate = ""  # handle stream's audio bitrate
-        self.__default_audio_samplerate = ""  # handle stream's audio samplerate
+        self.__default_video_resolution = ""  # handles stream resolution
+        self.__default_video_framerate = ""  # handles stream framerate
+        self.__default_video_bitrate = ""  # handles stream's video bitrate
+        self.__default_video_pixfmt = ""  # handles stream's video pixfmt
+        self.__default_video_decoder = ""  # handles stream's video decoder
+        self.__default_source_duration = ""  # handles stream's video duration
+        self.__approx_video_nframes = ""  # handles approx stream frame number
+        self.__default_audio_bitrate = ""  # handles stream's audio bitrate
+        self.__default_audio_samplerate = ""  # handles stream's audio samplerate
 
         # handle various stream flags
-        self.__contains_video = False  # contain video
-        self.__contains_audio = False  # contain audio
-        self.__contains_images = False  # contain image-sequence
+        self.__contains_video = False  # contains video
+        self.__contains_audio = False  # contains audio
+        self.__contains_images = False  # contains image-sequence
 
-        # check whether metadata probed or not
+        # handles output parameters through filters
+        self.__metadata_output = None  # handles output stream metadata
+        self.__output_frames_resolution = ""  # handles output stream resolution
+        self.__output_framerate = ""  # handles output stream framerate
+        self.__output_frames_pixfmt = ""  # handles output frame pixel format
+
+        # check whether metadata probed or not?
         self.__metadata_probed = False
 
     def probe_stream(self, default_stream_indexes=(0, 0)):
@@ -245,10 +251,26 @@ def probe_stream(self, default_stream_indexes=(0, 0)):
         if video_rfparams:
             self.__default_video_resolution = video_rfparams["resolution"]
             self.__default_video_framerate = video_rfparams["framerate"]
-        # parse pixel format
+
+        # parse output parameters through filters (if available)
+        if not (self.__metadata_output is None):
+            # parse output resolution and framerate
+            out_video_rfparams = self.__extract_resolution_framerate(
+                default_stream=default_stream_indexes[0], extract_output=True
+            )
+            if out_video_rfparams:
+                self.__output_frames_resolution = out_video_rfparams["resolution"]
+                self.__output_framerate = out_video_rfparams["framerate"]
+            # parse output pixel-format
+            self.__output_frames_pixfmt = self.__extract_video_pixfmt(
+                default_stream=default_stream_indexes[0], extract_output=True
+            )
+
+        # parse pixel-format
         self.__default_video_pixfmt = self.__extract_video_pixfmt(
             default_stream=default_stream_indexes[0]
         )
+
         # parse video decoder
         self.__default_video_decoder = self.__extract_video_decoder(
             default_stream=default_stream_indexes[0]
@@ -297,14 +319,15 @@ def probe_stream(self, default_stream_indexes=(0, 0)):
         # return reference to the instance object.
         return self
 
-    def retrieve_metadata(self, pretty_json=False):
+    def retrieve_metadata(self, pretty_json=False, force_retrieve_missing=False):
         """
         This method returns Parsed/Probed Metadata of the given source.
 
         Parameters:
             pretty_json (bool): whether to return metadata as JSON string(if `True`) or Dictionary(if `False`) type?
+            force_retrieve_output (bool): whether to also return metadata missing in current Pipeline. If `True` this method returns `(metadata, metadata_missing)` tuple instead of `metadata`.
 
-        **Returns:** metadata formatted as JSON string or python dictionary.
+        **Returns:** `metadata` or `(metadata, metadata_missing)` if `force_retrieve_output=True`, formatted as JSON string or python dictionary.
         """
         # check if metadata has been probed or not
         assert (
@@ -317,18 +340,23 @@ def retrieve_metadata(self, pretty_json=False):
             "ffmpeg_binary_path": self.__ffmpeg,
             "source": self.__source,
         }
+        metadata_missing = {}
         # Only either `source_demuxer` or `source_extension` attribute can be
         # present in metadata.
-        metadata.update(
-            {"source_extension": os.path.splitext(self.__source)[-1]}
-            if self.__source_demuxer is None
-            else {"source_demuxer": self.__source_demuxer}
-        )
+        if self.__source_demuxer is None:
+            metadata.update({"source_extension": os.path.splitext(self.__source)[-1]})
+            # update missing
+            force_retrieve_missing and metadata_missing.update({"source_demuxer": ""})
+        else:
+            metadata.update({"source_demuxer": self.__source_demuxer})
+            # update missing
+            force_retrieve_missing and metadata_missing.update({"source_extension": ""})
+        # add source video metadata properties
         metadata.update(
             {
                 "source_video_resolution": self.__default_video_resolution,
-                "source_video_framerate": self.__default_video_framerate,
                 "source_video_pixfmt": self.__default_video_pixfmt,
+                "source_video_framerate": self.__default_video_framerate,
                 "source_video_decoder": self.__default_video_decoder,
                 "source_duration_sec": self.__default_source_duration,
                 "approx_video_nframes": (
@@ -344,12 +372,38 @@ def retrieve_metadata(self, pretty_json=False):
                 "source_has_image_sequence": self.__contains_images,
             }
         )
+        # add output metadata properties (if available)
+        if not (self.__metadata_output is None):
+            metadata.update(
+                {
+                    "output_frames_resolution": self.__output_frames_resolution,
+                    "output_frames_pixfmt": self.__output_frames_pixfmt,
+                    "output_framerate": self.__output_framerate,
+                }
+            )
+        else:
+            # since output stream metadata properties are only available when additional
+            # FFmpeg parameters(such as filters) are defined manually, thereby missing
+            # output stream properties are handled by assigning them counterpart source
+            # stream metadata property values
+            force_retrieve_missing and metadata_missing.update(
+                {
+                    "output_frames_resolution": self.__default_video_resolution,
+                    "output_frames_pixfmt": self.__default_video_pixfmt,
+                    "output_framerate": self.__default_video_framerate,
+                }
+            )
         # log it
         self.__verbose_logs and logger.debug(
             "Metadata Extraction completed successfully!"
         )
-        # return metadata as either JSON string or Python dictionary
-        return json.dumps(metadata, indent=2) if pretty_json else metadata
+        # parse as JSON string(`json.dumps`), if defined
+        metadata = json.dumps(metadata, indent=2) if pretty_json else metadata
+        metadata_missing = (
+            json.dumps(metadata_missing, indent=2) if pretty_json else metadata_missing
+        )
+        # return `metadata` or `(metadata, metadata_missing)`
+        return metadata if not force_retrieve_missing else (metadata, metadata_missing)
 
     def __validate_source(self, source, source_demuxer=None, forced_validate=False):
         """
@@ -462,17 +516,41 @@ def __validate_source(self, source, source_demuxer=None, forced_validate=False):
             logger.error("`source` value is unusable or unsupported!")
             # discard the value otherwise
             raise ValueError("Input source is invalid. Aborting!")
-        # extract metadata
-        metadata = check_sp_output(
-            [self.__ffmpeg]
-            + (["-hide_banner"] if not self.__verbose_logs else [])
-            + self.__ffmpeg_prefixes
-            + (["-f", source_demuxer] if source_demuxer else [])
-            + ["-i", source],
-            force_retrieve_stderr=True,
+        # format command
+        if self.__sourcer_params:
+            # handle additional params separately
+            meta_cmd = (
+                [self.__ffmpeg]
+                + (["-hide_banner"] if not self.__verbose_logs else [])
+                + ["-t", "0.0001"]
+                + self.__ffmpeg_prefixes
+                + (["-f", source_demuxer] if source_demuxer else [])
+                + ["-i", source]
+                + dict2Args(self.__sourcer_params)
+                + ["-f", "null", "-"]
+            )
+        else:
+            meta_cmd = (
+                [self.__ffmpeg]
+                + (["-hide_banner"] if not self.__verbose_logs else [])
+                + self.__ffmpeg_prefixes
+                + (["-f", source_demuxer] if source_demuxer else [])
+                + ["-i", source]
+            )
+        # extract metadata, decode, and filter
+        metadata = (
+            check_sp_output(
+                meta_cmd,
+                force_retrieve_stderr=True,
+            )
+            .decode("utf-8")
+            .strip()
         )
-        # filter and return
-        return metadata.decode("utf-8").strip()
+        # separate input and output metadata (if available)
+        if "Output #" in metadata:
+            (metadata, self.__metadata_output) = metadata.split("Output #")
+        # return metadata based on params
+        return metadata
 
     def __extract_video_bitrate(self, default_stream=0):
         """
@@ -536,7 +614,7 @@ def __extract_video_decoder(self, default_stream=0):
                 return filtered_pixfmt[0].split(" ")[-1]
         return ""
 
-    def __extract_video_pixfmt(self, default_stream=0):
+    def __extract_video_pixfmt(self, default_stream=0, extract_output=False):
         """
         This Internal method parses default video-stream pixel-format from metadata.
 
@@ -546,11 +624,19 @@ def __extract_video_pixfmt(self, default_stream=0):
         **Returns:** Default Video pixel-format as string value.
         """
         identifiers = ["Video:", "Stream #"]
-        meta_text = [
-            line.strip()
-            for line in self.__ffsp_output.split("\n")
-            if all(x in line for x in identifiers)
-        ]
+        meta_text = (
+            [
+                line.strip()
+                for line in self.__ffsp_output.split("\n")
+                if all(x in line for x in identifiers)
+            ]
+            if not extract_output
+            else [
+                line.strip()
+                for line in self.__metadata_output.split("\n")
+                if all(x in line for x in identifiers)
+            ]
+        )
         if meta_text:
             selected_stream = meta_text[
                 default_stream
@@ -610,21 +696,31 @@ def __extract_audio_bitrate_nd_samplerate(self, default_stream=0):
             )
         return result if result and (len(result) == 2) else {}
 
-    def __extract_resolution_framerate(self, default_stream=0):
+    def __extract_resolution_framerate(self, default_stream=0, extract_output=False):
         """
         This Internal method parses default video-stream resolution and framerate from metadata.
 
         Parameters:
             default_stream (int): selects specific audio-stream in case of multiple ones.
+            extract_output (bool): Whether to extract from output(if true) or input(if false) stream?
 
         **Returns:** Default Video resolution and framerate as dictionary value.
         """
         identifiers = ["Video:", "Stream #"]
-        meta_text = [
-            line.strip()
-            for line in self.__ffsp_output.split("\n")
-            if all(x in line for x in identifiers)
-        ]
+        # use output metadata if available
+        meta_text = (
+            [
+                line.strip()
+                for line in self.__ffsp_output.split("\n")
+                if all(x in line for x in identifiers)
+            ]
+            if not extract_output
+            else [
+                line.strip()
+                for line in self.__metadata_output.split("\n")
+                if all(x in line for x in identifiers)
+            ]
+        )
         result = {}
         if meta_text:
             selected_stream = meta_text[
diff --git a/deffcode/utils.py b/deffcode/utils.py
index 7c6e427..8e477dc 100644
--- a/deffcode/utils.py
+++ b/deffcode/utils.py
@@ -78,7 +78,7 @@ def logger_handler():
 
 
 # define logger
-logger = logging.getLogger("Utilies")
+logger = logging.getLogger("Utilities")
 logger.propagate = False
 logger.addHandler(logger_handler())
 logger.setLevel(logging.DEBUG)
diff --git a/docs/recipes/advanced/transcode-art-filtergraphs.md b/docs/recipes/advanced/transcode-art-filtergraphs.md
index c4b1420..e30c5e0 100644
--- a/docs/recipes/advanced/transcode-art-filtergraphs.md
+++ b/docs/recipes/advanced/transcode-art-filtergraphs.md
@@ -121,7 +121,7 @@ decoder = FFdecoder("foo.mp4", frame_format="bgr24", verbose=True, **ffparams).f
 # retrieve framerate from source JSON Metadata and pass it as `-input_framerate`
 # parameter for controlled framerate and define other parameters
 output_params = {
-    "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"],
+    "-input_framerate": json.loads(decoder.metadata)["output_framerate"],
 }
 
 # Define writer with default parameters and suitable
@@ -198,7 +198,7 @@ decoder = FFdecoder(
 # retrieve framerate from source JSON Metadata and pass it as `-input_framerate`
 # parameter for controlled framerate and define other parameters
 output_params = {
-    "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"],
+    "-input_framerate": json.loads(decoder.metadata)["output_framerate"],
 }
 
 # Define writer with default parameters and suitable
@@ -266,7 +266,7 @@ decoder = FFdecoder(
 # retrieve framerate from source JSON Metadata and pass it as `-input_framerate`
 # parameter for controlled framerate and define other parameters
 output_params = {
-    "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"],
+    "-input_framerate": json.loads(decoder.metadata)["output_framerate"],
 }
 
 # Define writer with default parameters and suitable
@@ -334,7 +334,7 @@ decoder = FFdecoder(
 # retrieve framerate from source JSON Metadata and pass it as `-input_framerate`
 # parameter for controlled framerate and define other parameters
 output_params = {
-    "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"],
+    "-input_framerate": json.loads(decoder.metadata)["output_framerate"],
 }
 
 # Define writer with default parameters and suitable
diff --git a/docs/recipes/advanced/transcode-hw-acceleration.md b/docs/recipes/advanced/transcode-hw-acceleration.md
index 4eddb4a..89b5847 100644
--- a/docs/recipes/advanced/transcode-hw-acceleration.md
+++ b/docs/recipes/advanced/transcode-hw-acceleration.md
@@ -163,7 +163,7 @@ decoder = FFdecoder(
 # retrieve framerate from source JSON Metadata and pass it as `-input_framerate`
 # parameter for controlled framerate and define other parameters
 output_params = {
-    "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"],
+    "-input_framerate": json.loads(decoder.metadata)["output_framerate"],
     "-vcodec": "h264_nvenc",  # H.264 NVENC encoder
     "–resize": "1280x720",  # rescale to 1280x720
 }
diff --git a/docs/recipes/advanced/transcode-live-frames-complexgraphs.md b/docs/recipes/advanced/transcode-live-frames-complexgraphs.md
index d6c989e..53abc4c 100644
--- a/docs/recipes/advanced/transcode-live-frames-complexgraphs.md
+++ b/docs/recipes/advanced/transcode-live-frames-complexgraphs.md
@@ -122,7 +122,7 @@ decoder = FFdecoder(
 # retrieve framerate from source JSON Metadata and pass it as `-input_framerate`
 # parameter for controlled framerate and define other parameters
 output_params = {
-    "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"],
+    "-input_framerate": json.loads(decoder.metadata)["output_framerate"],
 }
 
 # Define writer with default parameters and suitable
diff --git a/docs/recipes/basic/transcode-live-frames-simplegraphs.md b/docs/recipes/basic/transcode-live-frames-simplegraphs.md
index 993240d..a0a2c19 100644
--- a/docs/recipes/basic/transcode-live-frames-simplegraphs.md
+++ b/docs/recipes/basic/transcode-live-frames-simplegraphs.md
@@ -85,7 +85,7 @@ In this example we will take the first 5 seconds of a video clip _(using [`trim`
 
 !!! info "OpenCV's `VideoWriter()` class requires a valid Output filename _(e.g. output_foo.avi)_, [FourCC](https://www.fourcc.org/fourcc.php) code, framerate, and resolution as input."
 
-!!! tip "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve source framerate and resolution."
+!!! tip "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve output framerate and resolution."
 
 !!! alert "By default, OpenCV expects `BGR` format frames in its `cv2.write()` method."
 
@@ -110,8 +110,8 @@ metadata_dict = json.loads(decoder.metadata)
 
 # prepare OpenCV parameters
 FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
-FRAMERATE = metadata_dict["source_video_framerate"]
-FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
+FRAMERATE = metadata_dict["output_framerate"]
+FRAMESIZE = tuple(metadata_dict["output_frames_resolution"])
 
 # Define writer with parameters and suitable output filename for e.g. `output_foo.avi`
 writer = cv2.VideoWriter("output_foo.avi", FOURCC, FRAMERATE, FRAMESIZE)
@@ -149,7 +149,7 @@ In this example we will crop real-time video frames by an area with size 2/3 of
 
 !!! info "OpenCV's `VideoWriter()` class requires a valid Output filename _(e.g. output_foo.avi)_, [FourCC](https://www.fourcc.org/fourcc.php) code, framerate, and resolution as input."
 
-!!! note "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve source framerate and resolution."
+!!! note "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve output framerate and resolution."
 
 !!! tip "More complex examples using `crop` filter can be found [here ➶](https://ffmpeg.org/ffmpeg-filters.html#toc-Examples-57) and can be applied similarly."
 
@@ -174,8 +174,8 @@ metadata_dict = json.loads(decoder.metadata)
 
 # prepare OpenCV parameters
 FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
-FRAMERATE = metadata_dict["source_video_framerate"]
-FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
+FRAMERATE = metadata_dict["output_framerate"]
+FRAMESIZE = tuple(metadata_dict["output_frames_resolution"])
 
 # Define writer with parameters and suitable output filename for e.g. `output_foo.avi`
 writer = cv2.VideoWriter("output_foo.avi", FOURCC, FRAMERATE, FRAMESIZE)
@@ -215,7 +215,7 @@ In this example we will rotate real-time video frames at an arbitrary angle by a
 
 !!! info "OpenCV's `VideoWriter()` class requires a valid Output filename _(e.g. output_foo.avi)_, [FourCC](https://www.fourcc.org/fourcc.php) code, framerate, and resolution as input."
 
-!!! note "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve source framerate and resolution."
+!!! note "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve output framerate and resolution."
 
 ```python
 # import the necessary packages
@@ -238,8 +238,8 @@ metadata_dict = json.loads(decoder.metadata)
 
 # prepare OpenCV parameters
 FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
-FRAMERATE = metadata_dict["source_video_framerate"]
-FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
+FRAMERATE = metadata_dict["output_framerate"]
+FRAMESIZE = tuple(metadata_dict["output_frames_resolution"])
 
 # Define writer with parameters and suitable output filename for e.g. `output_foo.avi`
 writer = cv2.VideoWriter("output_foo.avi", FOURCC, FRAMERATE, FRAMESIZE)
@@ -278,7 +278,7 @@ In this example we will rotate real-time video frames by 90 degrees counterclock
 
 !!! info "OpenCV's `VideoWriter()` class requires a valid Output filename _(e.g. output_foo.avi)_, [FourCC](https://www.fourcc.org/fourcc.php) code, framerate, and resolution as input."
 
-!!! note "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve source framerate and resolution."
+!!! note "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve output framerate and resolution."
 
 ```python
 # import the necessary packages
@@ -301,8 +301,8 @@ metadata_dict = json.loads(decoder.metadata)
 
 # prepare OpenCV parameters
 FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
-FRAMERATE = metadata_dict["source_video_framerate"]
-FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
+FRAMERATE = metadata_dict["output_framerate"]
+FRAMESIZE = tuple(metadata_dict["output_frames_resolution"])
 
 # Define writer with parameters and suitable output filename for e.g. `output_foo.avi`
 writer = cv2.VideoWriter("output_foo.avi", FOURCC, FRAMERATE, FRAMESIZE)
@@ -339,7 +339,7 @@ In this example we will horizontally flip and scale real-time video frames to ha
 
 !!! info "OpenCV's `VideoWriter()` class requires a valid Output filename _(e.g. output_foo.avi)_, [FourCC](https://www.fourcc.org/fourcc.php) code, framerate, and resolution as input."
 
-!!! note "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve source framerate and resolution."
+!!! note "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve output framerate and resolution."
 
 !!! tip "More complex examples using `scale` filter can be found [here ➶](https://ffmpeg.org/ffmpeg-filters.html#toc-Examples-107) and can be applied similarly."
 
@@ -364,8 +364,8 @@ metadata_dict = json.loads(decoder.metadata)
 
 # prepare OpenCV parameters
 FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
-FRAMERATE = metadata_dict["source_video_framerate"]
-FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
+FRAMERATE = metadata_dict["output_framerate"]
+FRAMESIZE = tuple(metadata_dict["output_frames_resolution"])
 
 # Define writer with parameters and suitable output filename for e.g. `output_foo.avi`
 writer = cv2.VideoWriter("output_foo.avi", FOURCC, FRAMERATE, FRAMESIZE)
diff --git a/docs/recipes/basic/transcode-live-frames.md b/docs/recipes/basic/transcode-live-frames.md
index 11f9cc7..7e873e2 100644
--- a/docs/recipes/basic/transcode-live-frames.md
+++ b/docs/recipes/basic/transcode-live-frames.md
@@ -87,10 +87,12 @@ In this example we will decode different pixel formats video frames from a given
 
 !!! info "OpenCV's `VideoWriter()` class requires a valid Output filename _(e.g. output_foo.avi)_, [FourCC](https://www.fourcc.org/fourcc.php) code, framerate, and resolution as input."
 
-!!! tip "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve source framerate and resolution."
+!!! tip "You can use FFdecoder's [`metadata`](../../reference/ffdecoder/#deffcode.ffdecoder.FFdecoder.metadata) property object that dumps source Video's metadata information _(as JSON string)_ to retrieve output framerate and resolution."
 
 !!! alert "By default, OpenCV expects `BGR` format frames in its `cv2.write()` method."
 
+!!! note "The `YUV` pixel-format frames are NOT yet supported by OpenCV VideoWriter, try using WriteGear API instead."
+
 === "BGR frames"
 
     ```python
@@ -106,8 +108,8 @@ In this example we will decode different pixel formats video frames from a given
 
     # prepare OpenCV parameters
     FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
-    FRAMERATE = metadata_dict["source_video_framerate"]
-    FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
+    FRAMERATE = metadata_dict["output_framerate"]
+    FRAMESIZE = tuple(metadata_dict["output_frames_resolution"])
 
     # Define writer with parameters and suitable output filename for e.g. `output_foo.avi`
     writer = cv2.VideoWriter("output_foo.avi", FOURCC, FRAMERATE, FRAMESIZE)
@@ -159,8 +161,8 @@ In this example we will decode different pixel formats video frames from a given
 
     # prepare OpenCV parameters
     FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
-    FRAMERATE = metadata_dict["source_video_framerate"]
-    FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
+    FRAMERATE = metadata_dict["output_framerate"]
+    FRAMESIZE = tuple(metadata_dict["output_frames_resolution"])
 
     # Define writer with parameters and suitable output filename for e.g. `output_foo.avi`
     writer = cv2.VideoWriter("output_foo.avi", FOURCC, FRAMERATE, FRAMESIZE)
@@ -204,8 +206,8 @@ In this example we will decode different pixel formats video frames from a given
 
     # prepare OpenCV parameters
     FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
-    FRAMERATE = metadata_dict["source_video_framerate"]
-    FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
+    FRAMERATE = metadata_dict["output_framerate"]
+    FRAMESIZE = tuple(metadata_dict["output_frames_resolution"])
 
     # Define writer with parameters and suitable output filename for e.g. `output_foo_gray.avi`
     writer = cv2.VideoWriter("output_foo_gray.avi", FOURCC, FRAMERATE, FRAMESIZE)
@@ -229,50 +231,6 @@ In this example we will decode different pixel formats video frames from a given
     writer.release()
     ```
 
-=== "YUV frames"
-
-    !!! info "OpenCV also directly consumes `YUV` format frames in its `cv2.write()` method."
-
-    !!! note "You can also use `yuv422p`(4:2:2 subsampling) or `yuv444p`(4:4:4 subsampling) instead in `frame_format` parameter for more higher dynamic range."
-
-    ```python
-    # import the necessary packages
-    from deffcode import FFdecoder
-    import json, cv2
-
-    # initialize and formulate the decoder for YUV420 output
-    decoder = FFdecoder("foo.mp4", frame_format="yuv420p", verbose=True).formulate()
-
-    # retrieve JSON Metadata and convert it to dict
-    metadata_dict = json.loads(decoder.metadata)
-
-    # prepare OpenCV parameters
-    FOURCC = cv2.VideoWriter_fourcc("M", "J", "P", "G")
-    FRAMERATE = metadata_dict["source_video_framerate"]
-    FRAMESIZE = tuple(metadata_dict["source_video_resolution"])
-
-    # Define writer with parameters and suitable output filename for e.g. `output_foo_yuv.avi`
-    writer = cv2.VideoWriter("output_foo_yuv.avi", FOURCC, FRAMERATE, FRAMESIZE)
-
-    # grab the YUV420 frame from the decoder
-    for frame in decoder.generateFrame():
-
-        # check if frame is None
-        if frame is None:
-            break
-
-        # {do something with the frame here}
-
-        # writing YUV420 frame to writer
-        writer.write(frame)
-
-    # terminate the decoder
-    decoder.terminate()
-
-    # safely close writer
-    writer.release()
-    ```
-
 &nbsp;
 
 ## Transcoding lossless video using WriteGear API
@@ -421,9 +379,11 @@ In this example we will decode different pixel formats video frames from a given
 
 === "YUV frames"
 
-    !!! info "WriteGear API also directly consumes `YUV` format frames in its `write()` class method. 
+    !!! info "WriteGear API can easily consumes `YUV` format frames in its `write()` class method only in compression mode."
+
+    !!! note "You can also use `yuv422p`(4:2:2 subsampling) or `yuv444p`(4:4:4 subsampling) instead for more higher dynamic ranges."
 
-    !!! note "You can also use `yuv422p`(4:2:2 subsampling) or `yuv444p`(4:4:4 subsampling) instead in `frame_format` parameter for more higher dynamic range."
+    !!! alert "In WriteGear API, the support for `-input_pixfmt` attribute in `output_params` dictionary parameter was added in `v0.3.0`."
 
     ```python
     # import the necessary packages
@@ -432,17 +392,19 @@ In this example we will decode different pixel formats video frames from a given
     import json
 
     # initialize and formulate the decoder for YUV420 output
-    decoder = FFdecoder("foo.mp4", frame_format="yuv420p", verbose=True).formulate()
+    decoder = FFdecoder("foo.mp4", frame_format="yuv420p").formulate()
 
-    # retrieve framerate from source JSON Metadata and pass it as `-input_framerate` parameter
-    # for controlled output framerate
+    # retrieve framerate from source JSON Metadata and pass it as 
+    # `-input_framerate` parameter for controlled framerate
+    # and add input pixfmt as yuv420p also
     output_params = {
-        "-input_framerate": json.loads(decoder.metadata)["source_video_framerate"]
+        "-input_framerate": json.loads(decoder.metadata)["output_framerate"],
+        "-input_pixfmt": "yuv420p"
     }
 
     # Define writer with default parameters and suitable
     # output filename for e.g. `output_foo_yuv.mp4`
-    writer = WriteGear(output_filename="output_foo_yuv.mp4", **output_params)
+    writer = WriteGear(output_filename="output_foo_yuv.mp4", logging=True, **output_params)
 
     # grab the YUV420 frame from the decoder
     for frame in decoder.generateFrame():
diff --git a/docs/reference/ffdecoder/params.md b/docs/reference/ffdecoder/params.md
index 58b9429..fe2eced 100644
--- a/docs/reference/ffdecoder/params.md
+++ b/docs/reference/ffdecoder/params.md
@@ -427,23 +427,34 @@ decoder = FFdecoder("foo.mp4", source_demuxer="dshow").formulate()
 
 ## **`frame_format`** 
 
-This parameter select the pixel format for output video frames _(such as `gray` for grayscale output)_. If not specified, its value defaults to `rgb24` _(24-bit RGB)_.
+This parameter select the pixel format for output video frames _(such as `gray` for grayscale output)_.
 
-!!! warning "Any invalid or unsupported value to `frame_format` parameter will discarded!"
+??? note "Any invalid or unsupported value to `frame_format` parameter will discarded!"
+
+    Any improper `frame_format` parameter value _(i.e. either `null`(special-case), undefined, or invalid type)_ , then `-pix_fmt` FFmpeg parameter value in Decoding pipeline uses `output_frames_pixfmt` metadata property extracted from Output Stream. Thereby, in case if no valid `output_frames_resolution`  metadata property is found, then API finally defaults to **Default pixel-format**[^1] _(calculated variably)_.
+
+    !!! alert "The `output_frame_pixfmt` metadata property is only available when FFmpeg filters via. `-vf` or `-filter_complex` are manually defined."
+
+
+??? info "Use `#!py3 frame_format="null"` to manually discard `-pix_fmt` FFmpeg parameter entirely from Decoding pipeline."
+
+    This feature allows users to manually skip `-pix_fmt` FFmpeg parameter in Decoding pipeline, essentially for using only `format` filter values, or even better, let FFmpeg itself choose the best available output frame pixel-format for the given source.
 
-!!! tip "Use `#!sh ffmpeg -pix_fmts` terminal command to lists all FFmpeg supported pixel formats."
 
 **Data-Type:** String
 
-**Default Value:** Its default value is `rgb24`
+**Default Value:** Its default value is **Default pixel-format**[^1] _(calculated variably)_.
 
 **Usage:**
 
+
 ```python
 # initialize and formulate the decoder for grayscale frames
 decoder = FFdecoder("foo.mp4", frame_format="gray").formulate()
 ```
 
+!!! tip "Use `#!sh ffmpeg -pix_fmts` terminal command to lists all FFmpeg supported pixel formats."
+
 !!! example "Various Pixel formats related usage recipes :material-pot-steam: can found [here ➶](../../../recipes/basic/decode-video-files/#capturing-and-previewing-bgr-frames-from-a-video-file)"
 
 &nbsp; 
@@ -486,7 +497,7 @@ FFdecoder("foo.mp4", custom_ffmpeg="/foo/foo1/ffmpeg").formulate()
 
 ## **`verbose`**
 
-This parameter enables verbose _(if `True`)_, essential for debugging. 
+This parameter enables verbose logs _(if `True`)_, essential for debugging. 
 
 **Data-Type:** Boolean
 
@@ -495,6 +506,7 @@ This parameter enables verbose _(if `True`)_, essential for debugging.
 **Usage:**
 
 ```python
+# initialize and formulate decoder with verbose logs
 FFdecoder("foo.mp4", verbose=True).formulate()
 ```
 
@@ -534,16 +546,17 @@ decoder = FFdecoder("foo.mp4", verbose=True, **ffparams).formulate()
 
 #### B. Exclusive Parameters
 
-> In addition to FFmpeg parameters, FFdecoder API also supports few Exclusive Parameters, to allow users to flexibly change its internal pipeline, properties, and handle some special FFmpeg parameters _(such as repeated `map`)_ that cannot be assigned via. python dictionary. 
+> In addition to FFmpeg parameters, FFdecoder API also supports few Exclusive Parameters to allow users to flexibly change its internal pipeline, properties, and handle some special FFmpeg parameters _(such as repeated `map`)_ that cannot be assigned via. python dictionary. 
 
 These parameters are discussed below:
 
-
 * **`-vcodec`** _(str)_ : This attribute works similar to `-vcodec` FFmpeg parameter for specifying supported decoders that are compiled with FFmpeg in use. If not specified, it's value is derived from source video metadata. Its usage is as follows: 
 
     !!! tip "Use `#!sh ffmpeg -decoders` terminal command to lists all FFmpeg supported decoders."
 
-    !!! info "To remove `-vcodec` forcefully from FFmpeg Pipeline, assign its value Nonetype as `#!py3 {"-vcodec":None}` in ffparams"
+    ??? info "Use `#!py3 {"-vcodec":None}` in ffparams to discard `-vcodec` FFmpeg parameter entirely from Decoding pipeline."
+
+        This feature allows users to manually skip `-vcodec` FFmpeg parameter in Decoding pipeline, for letting FFmpeg itself choose the best available video decoder for the given source.
 
     ```python
     # define suitable parameter
@@ -553,7 +566,19 @@ These parameters are discussed below:
 &ensp;
 
 
-* **`-framerate`** _(float/int)_ : This attribute works similar to `-framerate` FFmpeg parameter for generating video-frames at specified framerate. If not specified, it calculated from source video metadata. Its usage is as follows: 
+* **`-framerate`** _(float/int)_ : This attribute works similar to `-framerate` FFmpeg parameter for generating video-frames at specified framerate. If not specified, it calculated from video metadata. Its usage is as follows: 
+
+    ??? note "Any invalid or unsupported value to `-framerate` attribute will discarded!"
+
+        !!! alert "The `output_frames_framerate` metadata property is only available when FFmpeg filters via. `-vf` or `-filter_complex` are manually defined."
+
+        Any improper `-framerate` parameter value _(i.e. either `null`(special-case), undefined, or invalid type)_ , then `-framerate/-r` FFmpeg parameter value in Decoding pipeline uses `output_frames_framerate` metadata property extracted from Output Stream. Thereby, in case if no valid `output_framerate`  metadata property is found, then API finally defaults to `source_video_framerate` metadata property extracted from Input Source Stream.
+
+        !!! fail "In case neither `output_framerate` nor `source_video_framerate` valid metadata properties are found, then `RuntimeError` is raised."
+
+    ??? info "Use `#!py3 {"-framerate":"null"}` in ffparams to discard `-framerate/-r` FFmpeg parameter entirely from Decoding pipeline."
+
+        This feature allows users to manually skip `-framerate/-r` FFmpeg parameter in Decoding pipeline, essentially for using only `fps` filter values, or even better, let FFmpeg itself choose the best available output framerate for the given source.
 
     ```python
     # define suitable parameter
@@ -562,7 +587,19 @@ These parameters are discussed below:
 
 &ensp;
 
-* **`-custom_resolution`** _(tuple/list)_ : This attribute sets the custom resolution/size/dimensions of the output frames. Its value can either be a **tuple** => `(width,height)` or a **list** => `[width, height]`. If not specified, it calculated from source video metadata. Its usage is as follows: 
+* **`-custom_resolution`** _(tuple/list)_ : This attribute sets the custom resolution/size of the output frames. Its value can either be a **tuple** (`(width,height)`) or a **list** (`[width, height]`). If not specified, it calculated from video metadata. Its usage is as follows: 
+
+    ??? note "Any invalid or unsupported value to `-custom_resolution` attribute will discarded!"
+
+        !!! alert "The `output_frames_resolution` metadata property is only available when FFmpeg filters via. `-vf` or `-filter_complex` are manually defined."
+
+        Any improper `-custom_resolution` parameter value _(i.e. either `null`(special-case), undefined, or invalid type)_ , then `-s/-size` FFmpeg parameter value in Decoding pipeline uses `output_frames_resolution` metadata property extracted from Output Stream. Thereby, in case if no valid `output_frames_resolution`  metadata property is found, then API finally defaults to `source_video_resolution` metadata property extracted from Input Source Stream.
+
+        !!! fail "In case neither `output_frames_resolution` nor `source_video_resolution` valid metadata properties are found, then `RuntimeError` is raised."
+
+    ??? info "Use `#!py3 {"-custom_resolution":"null"}` in ffparams to discard `-size/-s` FFmpeg parameter entirely from Decoding pipeline."
+
+        This feature allows users to manually skip `-size/-s` FFmpeg parameter in Decoding pipeline, essentially for using only `fps` filter values, or even better, let FFmpeg itself choose the best available output frames resolution for the given source.
     
     ```python
     # define suitable parameter
@@ -603,7 +640,7 @@ These parameters are discussed below:
 
 &ensp;
 
-* **`-custom_sourcer_params`** _(dict)_ :  This attribute assigns parameter meant for Sourcer API's [`sourcer_params`](../../sourcer/params/#sourcer_params) dictionary parameter, directly through FFdecoder API. Its usage is as follows: 
+* **`-custom_sourcer_params`** _(dict)_ :  This attribute assigns all [**Exclusive Parameter**](../../sourcer/params/#exclusive-parameters) meant for Sourcer API's `sourcer_params` dictionary parameter directly through FFdecoder API. Its usage is as follows: 
     
     ```python
     # define suitable parameter meant for `sourcer_params`
@@ -612,10 +649,29 @@ These parameters are discussed below:
 
 &ensp;
 
+* **`-default_stream_indexes`** _(list/tuple)_ : This attribute assign value directly to `default_stream_indexes` parameter in Sourcer API's [`probe_stream()`](../../../reference/sourcer/#deffcode.sourcer.Sourcer.probe_stream) method for selecting specific video and audio stream index in case of multiple ones. Value can be of format: `(int,int)` or `[int,int]` as follows:
+    
+    ```python
+    # define suitable parameter meant for `probe_stream()` method
+    ffparams = {"-default_stream_indexes": (0,1)} # ("0th video stream", "1st audio stream")
+    ```
+
+&ensp;
+
 * **`-passthrough_audio`** _(bool/list)_ : _(Yet to be supported)_
 
 &nbsp; 
 
+[^1]: **Default pixel-format** is calculated variably in FFdecoder API:
+      
+      - [x] If `frame_format != "null"`: 
+        - If `frame_format` parameter is valid and supported: Default pixel-format is `frame_format` parameter value.
+        - If `frame_format` parameter is **NOT** valid or supported:
+            - If `output_frame_pixfmt` metadata is available: Default pixel-format is `output_frame_pixfmt` metadata value.
+            - If `output_frame_pixfmt` metadata is **NOT** available: Default pixel-format is `rgb24` if supported otherwise `source_video_pixfmt` metadata value.
+      - [x] If `frame_format == "null"`: Default pixel-format is `source_video_pixfmt` metadata value
+
+
 <!--
 External URLs
 -->
diff --git a/docs/reference/sourcer/params.md b/docs/reference/sourcer/params.md
index 5761fea..298b550 100644
--- a/docs/reference/sourcer/params.md
+++ b/docs/reference/sourcer/params.md
@@ -375,7 +375,7 @@ Sourcer("foo.mp4", custom_ffmpeg="/foo/foo1/ffmpeg").probe_stream()
 
 ## **`verbose`**
 
-This parameter enables verbose _(if `True`)_, essential for debugging. 
+This parameter enables verbose logs _(if `True`)_, essential for debugging. 
 
 **Data-Type:** Boolean
 
@@ -384,6 +384,7 @@ This parameter enables verbose _(if `True`)_, essential for debugging.
 **Usage:**
 
 ```python
+# initialize the sourcer with verbose logs
 Sourcer("foo.mp4", verbose=True).probe_stream()
 ```
 
@@ -394,49 +395,24 @@ Sourcer("foo.mp4", verbose=True).probe_stream()
 
 This dictionary parameter accepts all [Exclusive Parameters](#exclusive-parameters) formatted as its attributes:
 
+???+ note "Additional FFmpeg parameters"
+    
+    In addition to Exclusive Parameters, Sourcer API supports almost any FFmpeg parameter _(supported by installed FFmpeg)_, and thereby can be passed as dictionary attributes in `sourcer_params` parameter.
+
+    !!! danger "Kindly read [**FFmpeg Docs**](https://ffmpeg.org/documentation.html) carefully before passing any additional values to `sourcer_params` parameter. Wrong invalid values may result in undesired errors or no output at all."
+
+    !!! alert "All FFmpeg parameters are case-sensitive. Remember to double check every parameter if any error(s) occurred."
+
 **Data-Type:** Dictionary
 
 **Default Value:** Its default value is `{}`.
 
 ### Exclusive Parameters
 
-> In addition to FFmpeg parameters, Sourcer API also supports few Exclusive Parameters, to allow users to flexibly change its probing properties, and handle some special FFmpeg parameters.
+> Sourcer API supports few Exclusive Parameters to allow users to flexibly change its probing properties and handle some special FFmpeg parameters.
 
 These parameters are discussed below:
 
-
-* **`-vcodec`** _(str)_ : This attribute works similar to `-vcodec` FFmpeg parameter for specifying supported decoders that are compiled with FFmpeg in use. If not specified, it's value is derived from source video metadata. Its usage is as follows: 
-
-    !!! tip "Use `#!sh ffmpeg -decoders` terminal command to lists all FFmpeg supported decoders."
-
-    !!! info "To remove `-vcodec` forcefully from FFmpeg Pipeline, assign its value Nonetype as `#!py3 {"-vcodec":None}` in sourcer_params"
-
-    ```python
-    # define suitable parameter
-    sourcer_params = {"-vcodec": "h264"} # set decoder to `h264`
-    ```
-
-&ensp;
-
-
-* **`-framerate`** _(float/int)_ : This attribute works similar to `-framerate` FFmpeg parameter for generating video-frames at specified framerate. If not specified, it calculated from source video metadata. Its usage is as follows: 
-
-    ```python
-    # define suitable parameter
-    sourcer_params = {"-framerate": 60.0} # set input video source framerate to 60fps
-    ```
-
-&ensp;
-
-* **`-custom_resolution`** _(tuple/list)_ : This attribute sets the custom resolution/size/dimensions of the output frames. Its value can either be a **tuple** => `(width,height)` or a **list** => `[width, height]`. If not specified, it calculated from source video metadata. Its usage is as follows: 
-    
-    ```python
-    # define suitable parameter
-    sourcer_params = {"-output_dimensions": (1280,720)} # to produce a 1280x720 resolution/scale output video
-    ```
-
-&ensp;
-
 * **`-ffprefixes`** _(list)_: This attribute sets the special FFmpeg parameters that generally occurs at the very beginning _(such as `-re`)_ before input (`-i`) source. The FFmpeg parameters defined with this attribute can repeated more than once and maintains its original order in the FFmpeg command. Its value can be of datatype **`list`** only and its usage is as follows: 
 
     !!! tip "Turn on [`verbose`](#verbose) parameter _(`verbose = True`)_ to see the FFmpeg command that is being executed in Sourcer's pipeline. This helps you debug/address any issues and make adjustments accordingly."


Test patch:
diff --git a/tests/test_ffdecoder.py b/tests/test_ffdecoder.py
index 6c1c6d5..f404414 100644
--- a/tests/test_ffdecoder.py
+++ b/tests/test_ffdecoder.py
@@ -313,7 +313,7 @@ def test_seek_n_save(ffparams, pixfmts):
         filename and remove_file_safe(filename)
 
 
-test_data_class = [
+test_data = [
     (return_testvideo_path(), {"-c:v": "hevc"}, False),
     (
         return_generated_frames_path(return_static_ffmpeg()),
@@ -340,7 +340,7 @@ def test_seek_n_save(ffparams, pixfmts):
 ]
 
 
-@pytest.mark.parametrize("source, ffparams, result", test_data_class)
+@pytest.mark.parametrize("source, ffparams, result", test_data)
 def test_FFdecoder_params(source, ffparams, result):
     """
     Testing FFdecoder API with different parameters and save output
@@ -391,7 +391,7 @@ def test_FFdecoder_params(source, ffparams, result):
             remove_file_safe(f_name)
 
 
-test_data_class = [
+test_data = [
     (
         "/dev/video0",
         "v4l2",
@@ -413,7 +413,7 @@ def test_FFdecoder_params(source, ffparams, result):
 ]
 
 
-@pytest.mark.parametrize("source, source_demuxer, result", test_data_class)
+@pytest.mark.parametrize("source, source_demuxer, result", test_data)
 def test_camera_capture(source, source_demuxer, result):
     """
     Tests FFdecoder's realtime Webcam and Virtual playback capabilities
@@ -428,8 +428,108 @@ def test_camera_capture(source, source_demuxer, result):
             frame_format="bgr24",
             verbose=True,
         ).formulate()
-        # capture 10 camera frames
-        for i in range(10):
+        # capture 5 camera frames
+        for i in range(5):
+            # grab the bgr24 frame from the decoder
+            frame_recv = next(decoder.generateFrame(), None)
+            # check if frame is None
+            if frame_recv is None:
+                raise AssertionError("Test Failed!")
+    except Exception as e:
+        if result:
+            # catch errors
+            pytest.fail(str(e))
+        else:
+            pytest.xfail(str(e))
+    finally:
+        # terminate
+        not (decoder is None) and decoder.terminate()
+
+
+test_data = [
+    (
+        "null",  # discard frame_format
+        {
+            "-custom_resolution": "null",  # discard `-custom_resolution`
+            "-framerate": "null",  # discard `-framerate`
+            "-vf": "format=bgr24,scale=320:240,fps=60",  # format=bgr24, scale=320x240, framerate=60fps
+        },
+        True,
+    ),
+    (
+        "bgr24",  # this pixel-format must override filter `format=rgb24`
+        {
+            "-vf": "format=rgb24,scale=320:240,fps=60",  # format=rgb24, scale=320x240, framerate=60fps
+        },
+        True,
+    ),
+    (
+        "invalid",  # invalid frame_format
+        {
+            "-custom_resolution": "invalid",  # invalid `-custom_resolution`
+            "-framerate": "invalid",  # invalid `-framerate`
+            "-vf": "format=bgr24,scale=320:240,fps=60",  # format=bgr24, scale=320x240, framerate=60fps
+        },
+        True,
+    ),
+    (
+        "invalid2",  # invalid frame_format
+        {
+            "-custom_resolution": "invalid",  # invalid `-custom_resolution`
+            "-framerate": "null",  # discard `-framerate`
+        },
+        False,
+    ),
+    (
+        "invalid3",  # invalid frame_format
+        {
+            "-custom_resolution": "null",  # discard `-custom_resolution`
+            "-framerate": "invalid",  # invalid `-framerate`
+        },
+        False,
+    ),
+    (
+        "null",  # discard frame_format
+        {
+            "-custom_resolution": "null",  # discard `-custom_resolution`
+            "-framerate": "null",  # discard `-framerate`
+        },
+        True,
+    ),
+]
+
+
+@pytest.mark.parametrize("frame_format, ffparams, result", test_data)
+def test_discard_n_filter_params(frame_format, ffparams, result):
+    """
+    Tests FFdecoder's discarding FFmpeg parameters and using FFmpeg Filter
+    capabilities
+    """
+    decoder = None
+    try:
+        # initialize and formulate the decode with suitable source
+        if not frame_format in ["invalid2", "invalid3"]:
+            decoder = FFdecoder(
+                return_testvideo_path(),
+                frame_format=frame_format,
+                verbose=True,
+            ).formulate()
+        else:
+            decoder = FFdecoder(
+                return_testvideo_path(),
+                frame_format=frame_format,
+                verbose=True,
+            )
+            # assign manually pix-format via `metadata` property object {special case}
+            decoder.metadata = (
+                {"source_video_resolution": [0], "output_frames_resolution": [0]}
+                if frame_format == "invalid2"
+                else {"source_video_framerate": 0.0, "output_framerate": 0.0}
+            )
+            # formulate decoder
+            decoder.formulate()
+        # capture 2 camera frames
+        for i in range(2):
             # grab the bgr24 frame from the decoder
             frame_recv = next(decoder.generateFrame(), None)
             # check if frame is None
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 38ca1a5..18fb6cf 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -27,7 +27,7 @@
 from deffcode.utils import dict2Args, logger_handler, delete_file_safe
 
 # define test logger
-logger = logging.getLogger("Test_utils")
+logger = logging.getLogger("Test_Utilities")
 logger.propagate = False
 logger.addHandler(logger_handler())
 logger.setLevel(logging.DEBUG)