Go Media Framework

Go FFmpeg Bindings

Installation

Prerequisites

Current master branch supports all major Go versions, starting from 1.6.

Build/install FFmpeg

build lastest version of ffmpeg, obtained from https://github.com/FFmpeg/FFmpeg
There is one required option, which is disabled by default, you should turn on: --enable-shared

E.g.:

./configure --prefix=/usr/local/ffmpeg --enable-shared
make
make install

Add pkgconfig path:

export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/ffmpeg/lib/pkgconfig/

Ensure, that PKG_CONFIG_PATH contains path to ffmpeg's pkgconfig folder.

# check it by running
pkg-config --libs libavformat

It should print valid path to the avformat library.

Now, just run

go get github.com/3d0c/gmf
Other methods

This package uses pkg-config way to obtain flags, includes and libraries path, so if you have ffmpeg installed, just ensure, that your installation has them (pkgconfig/ folder with proper pc files).

Docker containers

Thanks to @ergoz you can try a docker container riftbit/ffalpine

Thanks to @denismakogon there is one more project, worth to mention https://github.com/denismakogon/ffmpeg-debian

Usage

Please see examples.

Support and Contribution

If something doesn't work, just fix it. Do not hesitate to pull request.

Credits

I borrowed the name from project, abandoned on code.google.com/p/gmf. Original code is available here in intitial commit from 03 Apr 2013.

Comments
  • mp4s-to-flv.go produce wrong video length

    mp4s-to-flv.go produce wrong video length

    i tried runing mp4s-to-flv.go from examples, with bbb.mp4 file from same folder , unexpectedly , it produces a longer video than the original one , 01:00 -> 01:45 . also the produced audio and video seems out of sync .

  • Go - Cross Compilation for ARM

    Go - Cross Compilation for ARM

    Everything working fine with amd64 but when we are compiling it for arm, after setting GOARCH=arm, it is giving it below error, please advise how to solve it

    src/Manager/MediaManager.go:28: undefined: FmtCtx src/MediaManager.go:28: undefined: Stream src/Manager/MediaManager.go:29: undefined: CodecCtx src/Manager/MediaManager.go:30: undefined: Stream src/Manager/MediaManager.go:32: undefined: FindEncoder src/Manager/MediaManager.go:32: undefined: Codec src/Manager/MediaManager.go:40: undefined: NewCodecCtx src/Manager/MediaManager.go:46: undefined: CODEC_FLAG_GLOBAL_HEADER src/Manager/MediaManager.go:50: undefined: FF_COMPLIANCE_EXPERIMENTAL src/Manager/MediaManager.go:53: undefined: AVMEDIA_TYPE_AUDIO

    Regards,

  • C.av_codec_iterate

    C.av_codec_iterate

    Hi, I am trying to install Live Stream Analyzer on my Raspberry Pi 3B+ (Raspbian Kernel 4.14.98-v7+) for which gmf is a prerequisite. I installed ffmpeg Version 3.2.12-1 via apt-get including all development packages (libavutil-dev, libavcodec-dev, etc.)

    libavutil 55. 34.101 / 55. 34.101 libavcodec 57. 64.101 / 57. 64.101 libavformat 57. 56.101 / 57. 56.101 libavdevice 57. 1.100 / 57. 1.100 libavfilter 6. 65.100 / 6. 65.100 libavresample 3. 1. 0 / 3. 1. 0 libswscale 4. 2.100 / 4. 2.100 libswresample 2. 3.100 / 2. 3.100 libpostproc 54. 1.100 / 54. 1.100

    Unfortunately "go get" installation of gmf exit with the following error message:

    #github.com/3d0c/gmf could not determine kind of name for C.av_codec_iterate

    Thankful for any hints to solve this issue.

    Cheers Jens

  • Bugfixes

    Bugfixes

    This pull resolves the following compile errors/warnings:

    packet.go:61:2: warning: 'av_free_packet' is deprecated [-Wdeprecated-declarations]
    /usr/local/ffmpeg/include/libavcodec/avcodec.h:4040:6: note: 'av_free_packet' has been explicitly marked deprecated here
    
    codecCtx.go:285: cannot use C.int(val) (type C.int) as type C.int64_t in assignment
    packet.go:193: cannot use C.int(duration) (type C.int) as type C.int64_t in assignment
    
  • Possibility to return the data after ImgAlloc()

    Possibility to return the data after ImgAlloc()

    Is there any possibility to get the data of the frame, after I call Frame.ImgAlloc()? Only errors will returned if there any or does I not see the right point?

    func (this *Frame) ImgAlloc() error {
        if ret := int(C.av_image_alloc(
            (**C.uint8_t)(unsafe.Pointer(&this.avFrame.data)),
            (*_Ctype_int)(unsafe.Pointer(&this.avFrame.linesize)),
            C.int(this.Width()), C.int(this.Height()), int32(this.Format()), 32)); ret < 0 {
            return errors.New(fmt.Sprintf("Unable to allocate raw image buffer: %v", AvError(ret)))
        }
    
        return nil
    }
    
  • Added a method to get Frame.avFrame

    Added a method to get Frame.avFrame

    Hi @3d0c, I needed to work with raw AVFrame, so I added Frame.GetRawFrame() which returns *AVFrame, raw pointer to C struct.

    It might be useful to work with FFMpeg APIs outside of gmf.

    For example, I needed to flip frames vertically while encoding to show frames in OpenGL window. In OpenGL the origin is located on left-bottom corner so basically we have to invert images.

    We can achieve this with filters, but I wanted to do it using sws_scale for performance sake. If we can get raw *AVFrame it can be done like this:

    /*
    #include "libavutil/frame.h"
    
    // Modify frame->data and frame->linesize so that images will flip vertically on sws_scale
    // ref. http://www.ffmpeg-archive.org/Flip-in-sws-scale-td939665.html
    void flip_y(uint8_t** data, int* linesize, int width, int height) {
    	for (int i = 0; i < AV_NUM_DATA_POINTERS; i++) {
    		int h = (int)(height * ((float)linesize[i] / width));
    		data[i] += linesize[i] * (h - 1);
    		linesize[i] = -linesize[i];
    	}
    }
    */
    import "C"
    
    func main() {
    	...
    
    	// Get raw pointer to AVFrame
    	avFrame := (*C.struct_AVFrame)(unsafe.Pointer(frame.GetRawFrame()))
    
    	// Do the flip
    	C.flip_y(
    		(**C.uint8_t)(unsafe.Pointer(&avFrame.data)),
    		(*_Ctype_int)(unsafe.Pointer(&avFrame.linesize)),
    		C.int(frame.Width()),
    		C.int(frame.Height()),
    	)
    
    	// Call sws_scale as usual
    	v.swsCtx.Scale(frame, v.dstFrame)
    
    	...
    }
    
  • FIx video-to-image examples not working with H264 videos

    FIx video-to-image examples not working with H264 videos

    I tried video-to-xxx.go examples with H264/MP4 videos then I encountered several errors. This PR includes fixes to work with H264 videos.

    I used my own VJ loops and other H264 videos downloaded from beeple.

    Retry decoding if err is EAGAIN 034ff4f

    When I run video-to-image.go with H264 file, it threw an error: Resource temporarily unavailable on packet.Frames(). The error message came from ffmpeg's EAGAIN, it means we should retry avcodec_receive_frame until it succeeds.

    • https://github.com/FFmpeg/FFmpeg/blob/master/libavutil/error.c#L66
    • https://ffmpeg.org/doxygen/4.1/group__lavc__decoding.html#ga11e6542c4e66d3028668788a1a74217c

    I added retry code to video-to-*.go files. It uses goto for simplicity, but if you don't like it I'll rewrite them with for loop.

    Set encoder's timebase in video-to-jpeg-p.go aebce39

    go run examples/video-to-jpeg-p.go foo.mp4 throws an error: [jpeg2000 @ 0x880dc00] The encoder timebase is not set.

    I set the codec context's timebase to srcVideoStream.TimeBase.AVR().

    Scale frames in video-to-mjpeg.go a557b34

    go run examples/video-to-mjpeg.go foo.mp4 throws an error: [mjpeg @ 0xc001200] Invalid pts (0) <= last (0)

    I noticed video-to-mjpeg.go was not converting frames with sws, so I added swsCtx.Scale(frame, dstFrame) before encoding. It works, but I'm not sure this is the right decision... 😅

    Use CLI args instead of flags, like other examples 62f2394

    video-to-jpeg-p.go takes input video from CLI flag while other examples takes input from CLI args. It's confusing, so I fixed it.


    BTW gmf is the best repo for video editing in go, thanks @3d0c ! 💪

  • Cannot build by golang 1.3

    Cannot build by golang 1.3

    system: Mac OSX 10.9 go version: go1.3 darwin/amd64 ffmpeg version 2.1.4 Copyright (c) 2000-2014 the FFmpeg developers built on Mar 3 2014 09:09:13 with Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn) configuration: --prefix=/opt/local --enable-swscale --enable-avfilter --enable-avresample --enable-libmp3lame --enable-libvorbis --enable-libopus --enable-libtheora --enable-libschroedinger --enable-libopenjpeg --enable-libmodplug --enable-libvpx --enable-libspeex --enable-libass --enable-libbluray --enable-gnutls --enable-fontconfig --enable-libfreetype --disable-indev=jack --disable-outdev=xv --mandir=/opt/local/share/man --enable-shared --enable-pthreads --cc=/usr/bin/clang --arch=x86_64 --enable-yasm --enable-gpl --enable-postproc --enable-libx264 --enable-libxvid libavutil 52. 48.101 / 52. 48.101 libavcodec 55. 39.101 / 55. 39.101 libavformat 55. 19.104 / 55. 19.104 libavdevice 55. 5.100 / 55. 5.100 libavfilter 3. 90.100 / 3. 90.100 libavresample 1. 1. 0 / 1. 1. 0 libswscale 2. 5.101 / 2. 5.101 libswresample 0. 17.104 / 0. 17.104 libpostproc 52. 3.100 / 52. 3.100

    when run "go run encoding.go" show some error. When use golang 1.2 is can work.but have other bug.

    github.com/3d0c/gmf

    ../avio.go:89: cannot use _Cfunc_avio_alloc_context(this.buffer, C.int(IO_BUFFER_SIZE), 0, unsafe.Pointer(ctx.avCtx), ptrRead, ptrWrite, ptrSeek) (type *C.struct_AVIOContext) as type *C.AVIOContext in assignment ../codec.go:49: cannot use _Cfunc_avcodec_find_decoder_by_name(cname) (type *C.struct_AVCodec) as type *C.AVCodec in assignment ../codec.go:53: cannot use _Cfunc_avcodec_find_decoder(uint32(i.(int))) (type *C.struct_AVCodec) as type *C.AVCodec in assignment ../codec.go:75: cannot use _Cfunc_avcodec_find_encoder_by_name(cname) (type *C.struct_AVCodec) as type *C.AVCodec in assignment ../codec.go:79: cannot use _Cfunc_avcodec_find_encoder(uint32(i.(int))) (type *C.struct_AVCodec) as type *C.AVCodec in assignment ../codecCtx.go:94: cannot use codec.avCodec (type *C.AVCodec) as type *C.struct_AVCodec in argument to _Cfunc_avcodec_alloc_context3 ../codecCtx.go:99: cannot use codec.avCodec (type *C.AVCodec) as type *C.struct_AVCodec in argument to _Cfunc_avcodec_get_context_defaults3 ../codecCtx.go:101: cannot use codecctx (type *C.struct_AVCodecContext) as type *C.AVCodecContext in assignment ../codecCtx.go:173: cannot use this.avCodecCtx (type *C.AVCodecContext) as type *C.struct_AVCodecContext in argument to _Cfunc_avcodec_open2 ../codecCtx.go:173: cannot use this.codec.avCodec (type *C.AVCodec) as type *C.struct_AVCodec in argument to _Cfunc_avcodec_open2 ../codecCtx.go:173: too many errors

  • Problem with transcode an h264 video

    Problem with transcode an h264 video

    For further work I tried to transcode an H264/AVC Video (record with an iPhone) like your provided example. It creates an valid video file but many frames are dropped and the message [mpeg4 @ 0x580aa00] warning, too many b frames in a row is thrown many times. I'm not sure why that happens. I already tried to use the CopyExtra(ist *Stream) *CodecCtx to get more Information from the incoming stream, but it doesn't help. Do you have any suggestion or did you have a similar problem with transcoding?

  • Support for avformat_open_input options

    Support for avformat_open_input options

    Previous to this commit, no options could be given to the FmtCtx.OpenInput function. For input formats like video4linux2, that means options to specify input format (rawvideo, h264, etc.) or framerate were impossible.

    This commit introduces a new FmtCtx.OpenInputWithOption function that takes a Option parameter. To maintain backwards compatibility, the OpenInput function now just calls the OpenInputWithOption function, but passes a nil value for the Option parameter.

    Example usage:

      inputOptionsDict := gmf.NewDict([]gmf.Pair{
              {"white_balance_auto_preset","4"},
              {"input_format", "h264"},
      })
    
      inputCtx := gmf.NewCtx()
      inputCtx.SetInputFormat("video4linux2")
    
      inputOption := &gmf.Option{Key: "video4linux_input_options", Val: inputOptionsDict}
    
      err := inputCtx.OpenInputWithOption("/dev/video0", inputOption)
    
  • Memory leak fix

    Memory leak fix

    Various memory leaks has been fixed. If you still face some, please refer to "examples/stress.go" to see how to proper cleanup allocated instances.

  • Error handling

    Error handling

    Hello, I just started to use this package and I stumbled across some interesting behavior, I noticed that whenever a syscall.EAGAIN is received no error is returned and potentially a nil value is also returned. Example 1 Example 2

    Typically in Go you would propagate an error like this to allow the application layer to be able to change behavior.

    Is there a particular reason for not propagating the error?

  • memory leak

    memory leak

    When running test video-to-image.go with valgrind, got the following results:

    ==198162== HEAP SUMMARY:
    ==198162==     in use at exit: 239,337 bytes in 1,148 blocks
    ==198162==   total heap usage: 3,978 allocs, 2,830 frees, 18,270,904 bytes allocated
    ==198162== 
    ==198162== 128 (24 direct, 104 indirect) bytes in 1 blocks are definitely lost in loss record 296 of 349
    ==198162==    at 0x4848DD0: memalign (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==198162==    by 0x4848F32: posix_memalign (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==198162==    by 0x64D5474: av_malloc (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.70.100)
    ==198162==    by 0x64D5851: av_mallocz (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.70.100)
    ==198162==    by 0x64B2347: av_buffer_create (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.70.100)
    ==198162==    by 0x64B28EB: av_buffer_realloc (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.70.100)
    ==198162==    by 0x525946D: av_new_packet (in /usr/lib/x86_64-linux-gnu/libavcodec.so.58.134.100)
    ==198162==    by 0x4AB06D: _cgo_6590a2dc699d_Cfunc_av_new_packet (k:55)
    ==198162==    by 0x4637EF: runtime.asmcgocall.abi0 (asm_amd64.s:765)
    ==198162==    by 0x59F0DF: ???
    ==198162== 
    ==198162== 3,200 (600 direct, 2,600 indirect) bytes in 25 blocks are definitely lost in loss record 344 of 349
    ==198162==    at 0x4848DD0: memalign (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==198162==    by 0x4848F32: posix_memalign (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==198162==    by 0x64D5474: av_malloc (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.70.100)
    ==198162==    by 0x64D5851: av_mallocz (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.70.100)
    ==198162==    by 0x64B2347: av_buffer_create (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.70.100)
    ==198162==    by 0x64B28EB: av_buffer_realloc (in /usr/lib/x86_64-linux-gnu/libavutil.so.56.70.100)
    ==198162==    by 0x525946D: av_new_packet (in /usr/lib/x86_64-linux-gnu/libavcodec.so.58.134.100)
    ==198162==    by 0x4AB06D: _cgo_6590a2dc699d_Cfunc_av_new_packet (k:55)
    ==198162==    by 0x4637EF: runtime.asmcgocall.abi0 (asm_amd64.s:765)
    ==198162==    by 0x42C476: runtime.unlockWithRank (lockrank_off.go:32)
    ==198162==    by 0x42C476: runtime.unlock (lock_futex.go:112)
    ==198162==    by 0x42C476: runtime.removefinalizer (mheap.go:1846)
    ==198162==    by 0x327: ???
    ==198162==    by 0xC00000019F: ???
    ==198162== 
    ==198162== LEAK SUMMARY:
    ==198162==    definitely lost: 624 bytes in 26 blocks
    ==198162==    indirectly lost: 2,704 bytes in 52 blocks
    ==198162==      possibly lost: 3,280 bytes in 7 blocks
    ==198162==    still reachable: 230,713 bytes in 1,042 blocks
    ==198162==         suppressed: 0 bytes in 0 blocks
    

    The library is built with the latest release (4.4.2) of FFmpeg:

    libavutil      56. 70.100
    libavcodec     58.134.100
    libavformat    58. 76.100
    libavdevice    58. 13.100
    libavfilter     7.110.100
    libswscale      5.  9.100
    libswresample   3.  9.100
    libpostproc    55.  9.100
    
  • [Go-1.18] unable to instal gmf with `go install`

    [Go-1.18] unable to instal gmf with `go install`

    hey-hey, long time no see! I was restoring my docker images based on Go 1.18, as you know go get is no longer supported, so we need to use go install. Unfortunately, I can't install the package with go install, here's the output.

    
    $go install github.com/3d0c/gmf@latest
    go: downloading github.com/3d0c/gmf v0.0.0-20220425074253-5646e6e80daf
    package github.com/3d0c/gmf is not a main package
    
    $go version
    go version go1.18.1 linux/amd64
    
    
  • [question] example encoding-multiple mpeg4 can't play

    [question] example encoding-multiple mpeg4 can't play

    example encoding-multiple output 3 files: mpeg1, mpeg2, mpeg4. mpeg1 and mpeg2 work well, but mpeg4 can not be played. I don't know what's wrong, i need some help for fixed it.

    https://github.com/kaisawind/gmf/blob/master/example_encoding-multiple_test.go

    Screenshot_20211207_191628

  • ../format_go112.go:287:26: ctx.avCtx.filename undefined (type *_Ctype_struct_AVFormatContext has no field or method filename)

    ../format_go112.go:287:26: ctx.avCtx.filename undefined (type *_Ctype_struct_AVFormatContext has no field or method filename)

    Hello, why can't I find this method when I compile and install ffmpeg? Is there something wrong with my practice? I follow readme.md step by step.

    1634883378047

    root@fb0f71201404:/data/gmf/examples# pkg-config --libs libavformat libavdevice libavfilter -L/usr/local/ffmpeg/lib -lavformat -lavdevice -lavfilter

    ../format_go112.go:287:26: ctx.avCtx.filename undefined (type *_Ctype_struct_AVFormatContext has no field or method filename) ../format_go112.go:333:45: ctx.avCtx.filename undefined (type *_Ctype_struct_AVFormatContext has no field or method filename) ../format_go112.go:335:45: ctx.avCtx.filename undefined (type *_Ctype_struct_AVFormatContext has no field or method filename) ../frame_go112.go:114:24: f.avFrame.pkt_pts undefined (type *_Ctype_struct_AVFrame has no field or method pkt_pts) ../frame_go112.go:122:11: f.avFrame.pkt_pts undefined (type *_Ctype_struct_AVFrame has no field or method pkt_pts) ../stream.go:48:12: s.avStream.codec undefined (type *_Ctype_struct_AVStream has no field or method codec) ../stream.go:60:38: s.avStream.codec undefined (type *_Ctype_struct_AVStream has no field or method codec) ../stream.go:78:40: s.avStream.codec undefined (type *_Ctype_struct_AVStream has no field or method codec)

Related tags
A simple library to extract video and audio frames from media containers (based on libav).
A simple library to extract video and audio frames from media containers (based on libav).

Reisen A simple library to extract video and audio frames from media containers (based on libav, i.e. ffmpeg). Dependencies The library requires libav

Jan 2, 2023
Videncode - Media Encoder (with ffmpeg)

Videncode - Media Encoder (with ffmpeg) Powered by yellyoshua (With2 easy steps) - Build JSON with folder of videos > Process the videos to the new fo

Nov 19, 2022
Synthetic media is a realistic transformation of audio and video using artificial intelligence.

Synthetic media is a realistic transformation of audio and video using artificial intelligence.

Nov 20, 2021
Frf-media-download - This tool downloads all the files you have uploaded to FreeFeed

FreeFeed Media Downloader This tool downloads all the files you have uploaded to

Jan 29, 2022
A tool to stream videos📺 directly into VLC media player just by its name from terminal.
A tool to stream videos📺 directly into VLC media player just by its name from terminal.

PeerWatch A tool to stream videos directly into the VLC media player. Download Download the tool from here: Windows Linux win-x64 linux-x64 Building Y

Feb 12, 2022
[WIP] a very simple, tiny and intuitive ffmpeg wrapper with a cli interface for inspecting & transforming media files supported by the original ffmpeg software

About a very simple, tiny and intuitive ffmpeg wrapper with a cli interface for inspecting & transforming media files supported by the original ffmpeg

Oct 21, 2022
Using Mailchain, blockchain users can now send and receive rich-media HTML messages with attachments via a blockchain address.

Mailchain Introduction Mailchain enables blockchain-based email-like messaging with plain or rich text and attachment capabilities. Using blockchain p

Dec 28, 2022
Go bindings for libVLC and high-level media player interface
Go bindings for libVLC and high-level media player interface

Go bindings for libVLC 2.X/3.X/4.X and high-level media player interface. The package can be useful for adding multimedia capabilities to applications

Dec 31, 2022
Go bindings for libVLC and high-level media player interface
Go bindings for libVLC and high-level media player interface

Go bindings for libVLC 2.X/3.X/4.X and high-level media player interface. The package can be useful for adding multimedia capabilities to applications

Dec 31, 2022
a tool for creating exploited media files for discord

Discord-Exploits A program for creating exploited media files for discord written in Go. Usage discord-exploits is a command line utility, meaning you

Dec 29, 2021
Monitor newznab/torznab rss and add new media to sonarr/radarr

Nabarr Nabarr monitors Newznab/Torznab RSS feeds to find new media to add to Sonarr and or Radarr. Table of contents Installing nabarr Introduction Me

Dec 28, 2022
Ciak is a lightweight media server written in go
 Ciak is a lightweight media server written in go

Ciak allows you to show and stream your personal media tv series, movies, etc with a simple and clean web ui. The server also provide on the fly video encoding in order to stream non standard formats such as avi, mkv...

Jan 3, 2023
A simple library to extract video and audio frames from media containers (based on libav).
A simple library to extract video and audio frames from media containers (based on libav).

Reisen A simple library to extract video and audio frames from media containers (based on libav, i.e. ffmpeg). Dependencies The library requires libav

Jan 2, 2023
A social media API to handle users and their posts, written from scratch in Golang
A social media API to handle users and their posts, written from scratch in Golang

Initial Set-Up To start the project on your own machine you'll need Golang instlled, along with mongoDB. Once you've insured these requirements are me

Oct 9, 2021
Videncode - Media Encoder (with ffmpeg)

Videncode - Media Encoder (with ffmpeg) Powered by yellyoshua (With2 easy steps) - Build JSON with folder of videos > Process the videos to the new fo

Nov 19, 2022
WebRTC media servers stress testing tool (currently only Janus)
 WebRTC media servers stress testing tool (currently only Janus)

GHODRAT WebRTC media servers stress testing tool (currently only Janus) Architecture Janus media-server under load Deployment ghodrat # update or crea

Nov 9, 2022
A tui for playing media from a caddy fileserver

kwatch a little tui interface to play media from a caddy fileserver. options: -a: server address -u: server http username -p: server http password -o:

Aug 9, 2022
Synthetic media is a realistic transformation of audio and video using artificial intelligence.

Synthetic media is a realistic transformation of audio and video using artificial intelligence.

Nov 20, 2021
Preview media files in the shell
Preview media files in the shell

ffcat Output per stream preview directly in terminal. Supports image, audio and video files. Currently can only output via iTerm2 control codes. Be aw

Dec 17, 2022
Command-line tool to organize large directories of media files recursively by date, detecting duplicates.

go-media-organizer Command-line tool written in Go to organise all media files in a directory recursively by date, detecting duplicates.

Jan 6, 2022