Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deps.edn
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{:paths ["src" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.12.0-alpha3"}
:deps {org.clojure/clojure {:mvn/version "1.12.0"}
net.cgrand/xforms {:mvn/version "0.19.5"}
com.phronemophobic/clong {:mvn/version "1.4.2"}
org.clojure/data.priority-map {:mvn/version "1.1.0"}
Expand Down
3 changes: 2 additions & 1 deletion src/com/phronemophobic/clj_media.clj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
[com.phronemophobic.clj-media.impl.raw :as raw]
[com.phronemophobic.clj-media.impl.av :as av]))

(set! *warn-on-reflection* true)

(def sample-formats
"All possible sample formats."
Expand Down Expand Up @@ -174,7 +175,7 @@
(transduce
(comp
(map mm/byte-buffer)
(map (fn [buf]
(map (fn [^java.nio.ByteBuffer buf]
(let [bytes (byte-array (.capacity buf))]
(.get buf bytes)
bytes))))
Expand Down
31 changes: 17 additions & 14 deletions src/com/phronemophobic/clj_media/impl/audio.clj
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@

(def format-ctx (avformat_alloc_context))
(def format-ctx* (doto (PointerByReference.)
(.setValue (.getPointer format-ctx))))
(.setValue (Structure/.getPointer format-ctx))))

(avformat_open_input format-ctx*
fname
Expand Down Expand Up @@ -204,7 +204,7 @@
(.drain source-data-line)
(.close source-data-line)
read-bytes)
([read-bytes buf]
([read-bytes ^byte/1 buf]
(+ read-bytes
(.write source-data-line buf 0 (alength buf))))))))

Expand All @@ -217,19 +217,19 @@
(:nb_samples frame )
(:channels frame ))
buf (-> (nth (:data frame ) 0)
(.getPointer )
Structure/.getPointer
(.getByteArray 0 buf-size))]

buf)))))

(defn resample2 [input-format output-format]
(let [resample-ctx* (PointerByReference. Pointer/NULL)
err (swr_alloc_set_opts2 resample-ctx*
(.getPointer
(Structure/.getPointer
(:ch-layout output-format))
(:sample-format output-format)
(:sample-rate output-format)
(.getPointer
(Structure/.getPointer
(:ch-layout input-format))
(:sample-format input-format)
(:sample-rate input-format)
Expand Down Expand Up @@ -269,8 +269,11 @@
output-format
ch-layout (AVChannelLayout.)]
;; create out own copy since original copy may change :(
(av_channel_layout_copy (.getPointer ch-layout)
(.getPointer (:ch-layout output-format)))
(av_channel_layout_copy (Structure/.getPointer ch-layout)
(Structure/.getPointer (:ch-layout output-format)))
(comment
(supers AVChannelLayout)
)
(fn []
(let [frame
(doto (av/new-frame)
Expand All @@ -281,8 +284,8 @@
(.writeField "sample_rate" sample-rate))]
(assert
(zero? (av_channel_layout_copy
(.getPointer (:ch_layout frame))
(.getPointer ch-layout))))
(Structure/.getPointer (:ch_layout frame))
(Structure/.getPointer ch-layout))))
(assert
(>= (av_frame_get_buffer frame 0)
0))
Expand All @@ -297,7 +300,7 @@

output-frame* (volatile!
(new-output-frame))]
(assert (<= num-output-channels (alength (:data (AVFrame.)))))
(assert (<= num-output-channels (alength ^byte/1 (:data (AVFrame.)))))
(fn [rf]
(fn
([] (rf))
Expand All @@ -313,9 +316,9 @@

data-ptr (into-array Pointer
(eduction
(map (fn [p]
(map (fn [^AVChannelLayout p]
(when p
(.share (.getPointer p)
(.share (Structure/.getPointer p)
(* sample-offset-multiplier
current-samples)))))
(:data output-frame)))
Expand Down Expand Up @@ -349,7 +352,7 @@
(eduction
(map (fn [p]
(when p
(.share (.getPointer p)
(.share (Structure/.getPointer p)
(* sample-offset-multiplier
current-samples)))))
(:data output-frame)))
Expand Down Expand Up @@ -384,7 +387,7 @@
(let [buf-size (first (:linesize frame))
buf (-> (:data frame)
(nth 0)
(.getPointer)
(Structure/.getPointer)
(.getByteBuffer 0 buf-size))]
buf))

Expand Down
78 changes: 43 additions & 35 deletions src/com/phronemophobic/clj_media/impl/av.clj
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,18 @@
com.sun.jna.Structure)
(:gen-class))

(set! *warn-on-reflection* true)

(raw/import-structs!)

(def cleaner (Cleaner/create))
(def ^Cleaner cleaner (Cleaner/create))

(defonce handles (atom #{}))
(defn ref! [o]
(swap! handles conj o)
o)

(defn ->avrational [num den]
(defn ->avrational ^AVRational [num den]
(doto (AVRational.)
(.writeField "num" (int num))
(.writeField "den" (int den))))
Expand All @@ -40,13 +42,13 @@
(defn error->str [err]
(let [buf (byte-array 255)]
(av_strerror err buf (alength buf))
(let [s (String. buf 0 (transduce
(take-while #(not (zero? %)))
(completing
(fn [cnt _]
(inc cnt)))
0
buf))]
(let [s (String. buf 0 (long (transduce
(take-while #(not (zero? %)))
(completing
(fn [cnt _]
(inc cnt)))
0
buf)))]
s)))


Expand All @@ -60,8 +62,8 @@



(defn next-packet [ctx]
(let [packet (av_packet_alloc)
(defn next-packet [^AVFormatContext ctx]
(let [^AVPacket packet (av_packet_alloc)
ptr (Pointer/nativeValue (.getPointer packet))]
(.register cleaner packet
(fn []
Expand Down Expand Up @@ -94,10 +96,10 @@
(nativeType [_]
Pointer)
(toNative [_]
(.toNative frame)))
(com.sun.jna.NativeMapped/.toNative frame)))

(defn new-frame []
(let [frame (av_frame_alloc)
(defn new-frame ^AVFrame []
(let [^AVFrame frame (av_frame_alloc)
ptr (Pointer/nativeValue (.getPointer frame))]
(.register cleaner frame
(fn []
Expand All @@ -111,7 +113,7 @@
frame))

(defn new-packet[]
(let [packet (av_packet_alloc)
(let [^AVPacket packet (av_packet_alloc)
ptr (Pointer/nativeValue (.getPointer packet))]
(.register cleaner packet
(fn []
Expand All @@ -130,7 +132,7 @@
(fn
([] (rf))
([result] (rf result))
([result format-context]
([result ^Structure format-context]
(loop [result result]
(let [packet (new-packet)
err (av_read_frame (.getPointer format-context) packet)
Expand Down Expand Up @@ -307,14 +309,15 @@
result)]
result))))

(defn open-context [fname]
(defn open-context
^AVFormatContext [fname]
(let [format-ctx (avformat_alloc_context)
_ (when (nil? format-ctx)
(throw (ex-info "Error allocating format context."
{:filename fname})))

format-ctx* (doto (PointerByReference.)
(.setValue (.getPointer format-ctx)))
(.setValue (Structure/.getPointer format-ctx)))
_ (.register cleaner format-ctx
(fn []
(avformat_free_context (.getValue format-ctx*))))
Expand Down Expand Up @@ -354,7 +357,7 @@
AVMEDIA_TYPE_AUDIO (audio-codec-context-format codec-context)
AVMEDIA_TYPE_VIDEO (video-codec-context-format codec-context)))

(defn add-stream [output-format-context encoder-context]
(defn add-stream [output-format-context ^AVCodecContext encoder-context]
(let [output-format (:oformat output-format-context)
output-format+ (Structure/newInstance AVOutputFormatByReference
output-format)
Expand Down Expand Up @@ -389,13 +392,14 @@
(throw (Exception. "Could not initialize stream params")))
stream))

(defn video-encoder-context [format]
(defn video-encoder-context ^AVCodecContext [format]
(let [codec-id (-> format :codec :id)

output-codec (avcodec_find_encoder codec-id)
_ (when (nil? output-codec)
(throw (Exception. "could not find encoder")))

^AVCodecContext
encoder-context (avcodec_alloc_context3 output-codec)
_ (when (nil? encoder-context)
(throw (Exception. "Could not create encoder")))
Expand Down Expand Up @@ -437,12 +441,13 @@
(.writeField "bit_rate" bit-rate)))]
encoder-context))

(defn audio-encoder-context [format]
(defn audio-encoder-context ^AVCodecContext [format]
(let [codec-id (-> format :codec :id)
output-codec (avcodec_find_encoder codec-id)
_ (when (nil? output-codec)
(throw (Exception. "could not find encoder")))

^AVCodecContext
encoder-context (avcodec_alloc_context3 output-codec)
_ (when (nil? encoder-context)
(throw (Exception. "Could not create encoder")))
Expand All @@ -451,11 +456,12 @@

sample-fmt (:sample-format format)
sample-rate (:sample-rate format)
^AVChannelLayout
ch-layout (:ch-layout format)

_ (assert
(zero? (av_channel_layout_copy
(.getPointer (:ch_layout encoder-context))
(AVChannelLayout/.getPointer (:ch_layout encoder-context))
(.getPointer ch-layout))))

_ (doto encoder-context
Expand All @@ -467,12 +473,12 @@

encoder-context))

(defn encoder-context [format]
(defn encoder-context ^AVCodecContext [format]
(case (:media-type format)
:media-type/video (video-encoder-context format)
:media-type/audio (audio-encoder-context format)))

(defn find-decoder-context [media-type format-context]
(defn find-decoder-context ^AVCodecContext [media-type ^AVFormatContext format-context]
(let [err (avformat_find_stream_info format-context nil)
_ (when (not (zero? err))
(throw (ex-info "Could not find stream info."
Expand All @@ -490,19 +496,21 @@
{:error-code best-stream
:media-type media-type})))
num-streams (.readField format-context "nb_streams")
streams (.getPointerArray
streams (Pointer/.getPointerArray
(.readField format-context "streams")
0 num-streams)
stream (aget streams best-stream)
stream+ (Structure/newInstance AVStreamByReference
stream)

codec-parameters (.readField stream+ "codecpar")
codec-id (.readField codec-parameters "codec_id" )
codec-id (Structure/.readField codec-parameters "codec_id" )
^AVCodec
decoder (avcodec_find_decoder codec-id)
_ (when (nil? decoder)
(throw (ex-info "Could not find decoder"
{:codec-id codec-id})))
^AVCodecContext
decoder-context (avcodec_alloc_context3 (.getPointer decoder))

_ (when (nil? decoder-context)
Expand Down Expand Up @@ -593,7 +601,7 @@
(throw (ex-info "Could not find stream info."
{:error-code err})))
num-streams (:nb_streams format-context)
streams (.getPointerArray
streams (Pointer/.getPointerArray
(.readField format-context "streams")
0 num-streams)

Expand Down Expand Up @@ -627,7 +635,7 @@
{:streams streams-info}))


(defn make-frame [{:keys [bytes
(defn make-frame [{:keys [^byte/1 bytes
format
time-base
key-frame?
Expand Down Expand Up @@ -682,22 +690,22 @@
(.writeField "sample_rate" sample-rate))
(assert
(zero? (raw/av_channel_layout_copy
(.getPointer (:ch_layout frame))
(.getPointer ch-layout))))
(Structure/.getPointer (:ch_layout frame))
(Structure/.getPointer ch-layout))))
(assert
(>= (raw/av_frame_get_buffer frame 0)
0))
;; linesize might not match the byte array size
;; since linesize is sometimes set for a particular alignment
;; I think line size is set by raw/av_frame_get_buffer
(when (> (alength bytes)
(aget (:linesize frame) 0))
(aget ^ints (:linesize frame) 0))
(throw (ex-info "Bytes are the wrong length for sample format."
{:frame m
:bytes bytes
:actual-size (alength bytes)
:expected-length (aget (:linesize frame) 0)})))
(.write (.getPointer (aget (:data frame) 0)) 0 bytes 0 (alength bytes)))
:expected-length (aget ^ints (:linesize frame) 0)})))
(.write (Structure/.getPointer (aget ^objects (:data frame) 0)) 0 bytes 0 (alength bytes)))

:media-type/video
(let [{:keys [pixel-format
Expand All @@ -711,14 +719,14 @@
(doto frame
(.writeField "linesize"
(doto (int-array 8)
(aset 0 line-size))))
(aset 0 (int line-size)))))
(throw (ex-info ":line-size must be set when creating video frames."
{:frame m})))
(assert
(>= (raw/av_frame_get_buffer frame 0)
0))

(.write (.getPointer (aget (:data frame) 0)) 0 bytes 0 (alength bytes)))
(.write (Structure/.getPointer (aget ^objects (:data frame) 0)) 0 bytes 0 (alength bytes)))

nil (throw (ex-info "frame requires `:media-type` to be set."
{:frame m})))
Expand Down
Loading