mirror of
https://github.com/Danile71/go-rtsp.git
synced 2025-10-06 08:37:07 +08:00
168 lines
4.5 KiB
Go
168 lines
4.5 KiB
Go
package rtsp
|
|
|
|
/*
|
|
#cgo LDFLAGS: -lavformat -lavutil -lavcodec
|
|
#include "ffmpeg.h"
|
|
*/
|
|
import "C"
|
|
import (
|
|
"fmt"
|
|
"unsafe"
|
|
)
|
|
|
|
type decoder struct {
|
|
index int
|
|
codecCtx *C.AVCodecContext
|
|
codec *C.AVCodec
|
|
swrContext *C.SwrContext
|
|
codecType int
|
|
}
|
|
|
|
func (decoder *decoder) Decode(packet *C.AVPacket) (pkt *Packet, err error) {
|
|
pkt = &Packet{}
|
|
|
|
pkt.streamIndex = int(packet.stream_index)
|
|
pkt.codecType = decoder.codecType
|
|
|
|
switch decoder.codecType {
|
|
case int(C.AVMEDIA_TYPE_AUDIO):
|
|
case int(C.AVMEDIA_TYPE_VIDEO):
|
|
default:
|
|
// do nothing
|
|
return
|
|
}
|
|
|
|
cerr := C.avcodec_send_packet(decoder.codecCtx, packet)
|
|
if int(cerr) != 0 {
|
|
err = fmt.Errorf("ffmpeg: avcodec_send_packet failed: %d", cerr)
|
|
return
|
|
}
|
|
|
|
frame := C.av_frame_alloc()
|
|
defer C.av_frame_free(&frame)
|
|
|
|
cerr = C.avcodec_receive_frame(decoder.codecCtx, frame)
|
|
if int(cerr) < 0 {
|
|
err = fmt.Errorf("ffmpeg: avcodec_receive_frame failed: %d", cerr)
|
|
return
|
|
}
|
|
|
|
switch decoder.codecType {
|
|
case C.AVMEDIA_TYPE_VIDEO:
|
|
pkt.width = int(frame.width)
|
|
pkt.height = int(frame.height)
|
|
|
|
var encPacket C.AVPacket
|
|
defer C.av_packet_unref(&encPacket)
|
|
|
|
switch frame.format {
|
|
case C.AV_PIX_FMT_NONE, C.AV_PIX_FMT_YUVJ420P:
|
|
if cerr = C.rtsp_avcodec_encode_jpeg(decoder.codecCtx, frame, &encPacket); cerr != C.int(0) {
|
|
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_jpeg failed: %d", cerr)
|
|
return
|
|
}
|
|
|
|
default:
|
|
if cerr = C.rtsp_avcodec_encode_jpeg_nv12(decoder.codecCtx, frame, &encPacket); cerr != C.int(0) {
|
|
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_jpeg_nv12 failed: %d", cerr)
|
|
return
|
|
}
|
|
}
|
|
|
|
pkt.data = make([]byte, int(encPacket.size))
|
|
copy(pkt.data, *(*[]byte)(unsafe.Pointer(&encPacket.data)))
|
|
|
|
case C.AVMEDIA_TYPE_AUDIO:
|
|
pkt.bitRate = int(decoder.codecCtx.bit_rate)
|
|
pkt.sampleRate = int(frame.sample_rate)
|
|
pkt.channels = int(frame.channels)
|
|
|
|
switch frame.format {
|
|
case C.AV_SAMPLE_FMT_FLTP:
|
|
if decoder.swrContext == nil {
|
|
layout := uint64(frame.channel_layout)
|
|
|
|
decoder.swrContext = C.swr_alloc_set_opts(nil, // we're allocating a new context
|
|
C.long(layout), // out_ch_layout
|
|
C.AV_SAMPLE_FMT_S16, // out_sample_fmt
|
|
frame.sample_rate, // out_sample_rate
|
|
|
|
C.long(layout), // in_ch_layout
|
|
decoder.codecCtx.sample_fmt, // in_sample_fmt
|
|
frame.sample_rate, // in_sample_rate
|
|
|
|
0, // log_offset
|
|
nil) // log_ctx
|
|
|
|
if cerr = C.swr_init(decoder.swrContext); cerr < C.int(0) {
|
|
decoder.swrContext = nil
|
|
err = fmt.Errorf("ffmpeg: swr_init failed: %d", cerr)
|
|
return
|
|
}
|
|
}
|
|
|
|
var encPacket C.AVPacket
|
|
defer C.av_packet_unref(&encPacket)
|
|
|
|
if cerr = C.rtsp_avcodec_encode_resample_wav(decoder.codecCtx, decoder.swrContext, frame, &encPacket); cerr < C.int(0) {
|
|
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_resample_wav failed: %d", cerr)
|
|
return
|
|
}
|
|
pkt.data = make([]byte, int(encPacket.size))
|
|
copy(pkt.data, *(*[]byte)(unsafe.Pointer(&encPacket.data)))
|
|
|
|
case C.AV_SAMPLE_FMT_S16:
|
|
var encPacket C.AVPacket
|
|
defer C.av_packet_unref(&encPacket)
|
|
|
|
if cerr = C.rtsp_avcodec_encode_wav(decoder.codecCtx, frame, &encPacket); cerr != C.int(0) {
|
|
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_wav failed: %d", cerr)
|
|
return
|
|
}
|
|
|
|
pkt.data = make([]byte, int(encPacket.size))
|
|
copy(pkt.data, *(*[]byte)(unsafe.Pointer(&encPacket.data)))
|
|
|
|
case C.AV_SAMPLE_FMT_S32:
|
|
if decoder.swrContext == nil {
|
|
layout := uint64(frame.channel_layout)
|
|
|
|
decoder.swrContext = C.swr_alloc_set_opts(nil, // we're allocating a new context
|
|
C.long(layout), // out_ch_layout
|
|
C.AV_SAMPLE_FMT_S16, // out_sample_fmt
|
|
frame.sample_rate, // out_sample_rate
|
|
|
|
C.long(layout), // in_ch_layout
|
|
decoder.codecCtx.sample_fmt, // in_sample_fmt
|
|
frame.sample_rate, // in_sample_rate
|
|
|
|
0, // log_offset
|
|
nil) // log_ctx
|
|
|
|
if cerr = C.swr_init(decoder.swrContext); cerr < C.int(0) {
|
|
decoder.swrContext = nil
|
|
err = fmt.Errorf("ffmpeg: swr_init failed: %d", cerr)
|
|
return
|
|
}
|
|
}
|
|
|
|
var encPacket C.AVPacket
|
|
defer C.av_packet_unref(&encPacket)
|
|
|
|
if cerr = C.rtsp_avcodec_encode_resample_wav(decoder.codecCtx, decoder.swrContext, frame, &encPacket); cerr < C.int(0) {
|
|
err = fmt.Errorf("ffmpeg: rtsp_avcodec_encode_resample_wav failed: %d", cerr)
|
|
return
|
|
}
|
|
pkt.data = make([]byte, int(encPacket.size))
|
|
copy(pkt.data, *(*[]byte)(unsafe.Pointer(&encPacket.data)))
|
|
default:
|
|
err = fmt.Errorf("ffmpeg: audio format %d not supported: %d", frame.format)
|
|
return
|
|
}
|
|
|
|
default:
|
|
}
|
|
|
|
return
|
|
}
|