format: add Format, format::Context and Stream
This commit is contained in:
parent
67efc8b686
commit
b7a015c79a
392
src/format/context.rs
Normal file
392
src/format/context.rs
Normal file
@ -0,0 +1,392 @@
|
|||||||
|
use std::ffi::CString;
|
||||||
|
use std::ptr;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use libc::{c_int, c_uint};
|
||||||
|
use ffi::*;
|
||||||
|
use ::{Error, Dictionary, Codec, Stream, Format};
|
||||||
|
use ::device;
|
||||||
|
|
||||||
|
pub struct Context<'a> {
|
||||||
|
pub ptr: *mut AVFormatContext,
|
||||||
|
|
||||||
|
input: bool,
|
||||||
|
_marker: PhantomData<&'a i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Context<'a> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
unsafe {
|
||||||
|
Context {
|
||||||
|
ptr: avformat_alloc_context(),
|
||||||
|
|
||||||
|
input: false,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input(ptr: *mut AVFormatContext) -> Self {
|
||||||
|
Context {
|
||||||
|
ptr: ptr,
|
||||||
|
|
||||||
|
input: true,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn streams(&'a self) -> StreamIter<'a> {
|
||||||
|
StreamIter::new(self.ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn devices(&'a self) -> Result<DeviceIter<'a>, Error> {
|
||||||
|
DeviceIter::new(self.ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn probe_score(&self) -> i32 {
|
||||||
|
unsafe {
|
||||||
|
av_format_get_probe_score(self.ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn video_codec(&'a self) -> Option<Codec<'a>> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = av_format_get_video_codec(self.ptr);
|
||||||
|
|
||||||
|
if ptr == ptr::null_mut() {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Some(Codec::wrap(ptr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_video_codec(&'a mut self, value: Codec<'a>) {
|
||||||
|
unsafe {
|
||||||
|
av_format_set_video_codec(self.ptr, value.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn audio_codec(&'a self) -> Option<Codec<'a>> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = av_format_get_audio_codec(self.ptr);
|
||||||
|
|
||||||
|
if ptr == ptr::null_mut() {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Some(Codec::wrap(ptr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_audio_codec(&'a mut self, value: Codec<'a>) {
|
||||||
|
unsafe {
|
||||||
|
av_format_set_audio_codec(self.ptr, value.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subtitle_codec(&'a self) -> Option<Codec<'a>> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = av_format_get_subtitle_codec(self.ptr);
|
||||||
|
|
||||||
|
if ptr == ptr::null_mut() {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Some(Codec::wrap(ptr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_subtitle_codec(&'a mut self, value: Codec<'a>) {
|
||||||
|
unsafe {
|
||||||
|
av_format_set_subtitle_codec(self.ptr, value.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data_codec(&'a self) -> Option<Codec<'a>> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = av_format_get_data_codec(self.ptr);
|
||||||
|
|
||||||
|
if ptr == ptr::null_mut() {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Some(Codec::wrap(ptr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_data_codec(&'a mut self, value: Codec<'a>) {
|
||||||
|
unsafe {
|
||||||
|
av_format_set_data_codec(self.ptr, value.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn packet(&'a self) -> Packet<'a> {
|
||||||
|
Packet::new(self.ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for Context<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if self.input {
|
||||||
|
avformat_close_input(&mut self.ptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
avformat_free_context(self.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Packet<'a> {
|
||||||
|
ptr: *mut AVFormatContext,
|
||||||
|
pkt: ::Packet,
|
||||||
|
|
||||||
|
_marker: PhantomData<&'a Context<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Packet<'a> {
|
||||||
|
pub fn new(ptr: *mut AVFormatContext) -> Self {
|
||||||
|
Packet { ptr: ptr, pkt: ::Packet::new(), _marker: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stream(&'a self) -> Stream<'a> {
|
||||||
|
unsafe {
|
||||||
|
Stream::wrap(*(*self.ptr).streams.offset(self.pkt.val.stream_index as isize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&mut self) -> Result<(), Error> {
|
||||||
|
unsafe {
|
||||||
|
match av_read_frame(self.ptr, &mut self.pkt.val) {
|
||||||
|
0 => Ok(()),
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&mut self) -> Result<bool, Error> {
|
||||||
|
unsafe {
|
||||||
|
match av_write_frame(self.ptr, &mut self.pkt.val) {
|
||||||
|
1 => Ok(true),
|
||||||
|
0 => Ok(false),
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for Packet<'a> {
|
||||||
|
type Target = ::Packet;
|
||||||
|
|
||||||
|
fn deref<'b>(&'b self) -> &'b ::Packet {
|
||||||
|
&self.pkt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StreamIter<'a> {
|
||||||
|
ptr: *const AVFormatContext,
|
||||||
|
cur: c_uint,
|
||||||
|
|
||||||
|
_marker: PhantomData<&'a Context<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> StreamIter<'a> {
|
||||||
|
pub fn new(ptr: *const AVFormatContext) -> Self {
|
||||||
|
StreamIter { ptr: ptr, cur: 0, _marker: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for StreamIter<'a> {
|
||||||
|
type Item = Stream<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||||
|
unsafe {
|
||||||
|
if self.cur >= (*self.ptr).nb_streams {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.cur += 1;
|
||||||
|
Some(Stream::wrap(*(*self.ptr).streams.offset((self.cur - 1) as isize)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DeviceIter<'a> {
|
||||||
|
ptr: *mut AVDeviceInfoList,
|
||||||
|
cur: c_int,
|
||||||
|
|
||||||
|
_marker: PhantomData<&'a i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DeviceIter<'a> {
|
||||||
|
pub fn new(ctx: *mut AVFormatContext) -> Result<Self, Error> {
|
||||||
|
unsafe {
|
||||||
|
let mut ptr: *mut AVDeviceInfoList = ptr::null_mut();
|
||||||
|
|
||||||
|
match avdevice_list_devices(ctx, &mut ptr) {
|
||||||
|
n if n < 0 =>
|
||||||
|
Err(Error::new(n)),
|
||||||
|
|
||||||
|
_ =>
|
||||||
|
Ok(DeviceIter { ptr: ptr, cur: 0, _marker: PhantomData })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default(&self) -> usize {
|
||||||
|
unsafe {
|
||||||
|
(*self.ptr).default_device as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for DeviceIter<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
avdevice_free_list_devices(&mut self.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for DeviceIter<'a> {
|
||||||
|
type Item = device::Info<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||||
|
unsafe {
|
||||||
|
if self.cur >= (*self.ptr).nb_devices {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.cur += 1;
|
||||||
|
Some(device::Info::wrap(*(*self.ptr).devices.offset((self.cur - 1) as isize)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open<'a>(path: &Path) -> Result<Context<'a>, Error> {
|
||||||
|
unsafe {
|
||||||
|
let mut ps = ptr::null_mut();
|
||||||
|
let path = path.as_os_str().to_cstring().unwrap().as_ptr();
|
||||||
|
let status = avformat_open_input(&mut ps, path, ptr::null_mut(), ptr::null_mut());
|
||||||
|
|
||||||
|
match status {
|
||||||
|
0 => {
|
||||||
|
let ctx = Context::input(ps);
|
||||||
|
|
||||||
|
match avformat_find_stream_info(ps, ptr::null_mut()) {
|
||||||
|
0 => Ok(ctx),
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_with<'a>(path: &Path, mut options: Dictionary) -> Result<Context<'a>, Error> {
|
||||||
|
unsafe {
|
||||||
|
let mut ps = ptr::null_mut();
|
||||||
|
let path = path.as_os_str().to_cstring().unwrap().as_ptr();
|
||||||
|
let opts = &mut options.ptr;
|
||||||
|
let status = avformat_open_input(&mut ps, path, ptr::null_mut(), opts);
|
||||||
|
|
||||||
|
av_dict_free(opts);
|
||||||
|
|
||||||
|
match status {
|
||||||
|
0 => {
|
||||||
|
let ctx = Context::input(ps);
|
||||||
|
|
||||||
|
match avformat_find_stream_info(ps, ptr::null_mut()) {
|
||||||
|
0 => Ok(ctx),
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_as<'a>(path: &Path, format: &Format) -> Result<Context<'a>, Error> {
|
||||||
|
if let &Format::Input(ref format) = format {
|
||||||
|
unsafe {
|
||||||
|
let mut ps = ptr::null_mut();
|
||||||
|
let path = path.as_os_str().to_cstring().unwrap().as_ptr();
|
||||||
|
let status = avformat_open_input(&mut ps, path, format.ptr, ptr::null_mut());
|
||||||
|
|
||||||
|
match status {
|
||||||
|
0 => {
|
||||||
|
let ctx = Context::input(ps);
|
||||||
|
|
||||||
|
match avformat_find_stream_info(ps, ptr::null_mut()) {
|
||||||
|
0 => Ok(ctx),
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(Error::new(AVERROR_BUG))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_as_with<'a>(path: &Path, format: &Format, mut options: Dictionary) -> Result<Context<'a>, Error> {
|
||||||
|
if let &Format::Input(ref format) = format {
|
||||||
|
unsafe {
|
||||||
|
let mut ps = ptr::null_mut();
|
||||||
|
let path = path.as_os_str().to_cstring().unwrap().as_ptr();
|
||||||
|
let opts = &mut options.ptr;
|
||||||
|
let status = avformat_open_input(&mut ps, path, format.ptr, opts);
|
||||||
|
|
||||||
|
av_dict_free(opts);
|
||||||
|
|
||||||
|
match status {
|
||||||
|
0 => {
|
||||||
|
let ctx = Context::input(ps);
|
||||||
|
|
||||||
|
match avformat_find_stream_info(ps, ptr::null_mut()) {
|
||||||
|
0 => Ok(ctx),
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
e => Err(Error::new(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Err(Error::new(AVERROR_BUG))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump(ctx: &Context, index: i32, url: Option<&str>) {
|
||||||
|
let url = if let Some(url) = url {
|
||||||
|
CString::new(url).unwrap().as_ptr()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ptr::null()
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
if ctx.input {
|
||||||
|
av_dump_format(ctx.ptr, index, url, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
av_dump_format(ctx.ptr, index, url, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
194
src/format/format.rs
Normal file
194
src/format/format.rs
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
use std::ptr;
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::str::from_utf8_unchecked;
|
||||||
|
|
||||||
|
use ffi::*;
|
||||||
|
|
||||||
|
pub enum Format {
|
||||||
|
Input(Input),
|
||||||
|
Output(Output),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Format {
|
||||||
|
pub fn name<'a>(&'a self) -> &'a str {
|
||||||
|
match self {
|
||||||
|
&Format::Input(ref f) => f.name(),
|
||||||
|
&Format::Output(ref f) => f.name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn description<'a>(&'a self) -> &'a str {
|
||||||
|
match self {
|
||||||
|
&Format::Input(ref f) => f.description(),
|
||||||
|
&Format::Output(ref f) => f.description()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extensions<'a>(&'a self) -> Vec<&'a str> {
|
||||||
|
match self {
|
||||||
|
&Format::Input(ref f) => f.extensions(),
|
||||||
|
&Format::Output(ref f) => f.extensions()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mime_types<'a>(&'a self) -> Vec<&'a str> {
|
||||||
|
match self {
|
||||||
|
&Format::Input(ref f) => f.mime_types(),
|
||||||
|
&Format::Output(ref f) => f.mime_types()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Input {
|
||||||
|
pub ptr: *mut AVInputFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Input {
|
||||||
|
pub fn wrap(ptr: *mut AVInputFormat) -> Self {
|
||||||
|
Input { ptr: ptr }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name<'a>(&'a self) -> &'a str {
|
||||||
|
unsafe {
|
||||||
|
from_utf8_unchecked(CStr::from_ptr((*self.ptr).name).to_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn description<'a>(&'a self) -> &'a str {
|
||||||
|
unsafe {
|
||||||
|
from_utf8_unchecked(CStr::from_ptr((*self.ptr).name).to_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extensions<'a>(&'a self) -> Vec<&'a str> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (*self.ptr).extensions;
|
||||||
|
|
||||||
|
if ptr == ptr::null() {
|
||||||
|
vec!()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
from_utf8_unchecked(CStr::from_ptr(ptr).to_bytes()).split(',').collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mime_types<'a>(&'a self) -> Vec<&'a str> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (*self.ptr).mime_type;
|
||||||
|
|
||||||
|
if ptr == ptr::null() {
|
||||||
|
vec!()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
from_utf8_unchecked(CStr::from_ptr(ptr).to_bytes()).split(',').collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Output {
|
||||||
|
pub ptr: *mut AVOutputFormat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Output {
|
||||||
|
pub fn wrap(ptr: *mut AVOutputFormat) -> Self {
|
||||||
|
Output { ptr: ptr }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name<'a>(&'a self) -> &'a str {
|
||||||
|
unsafe {
|
||||||
|
from_utf8_unchecked(CStr::from_ptr((*self.ptr).name).to_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn description<'a>(&'a self) -> &'a str {
|
||||||
|
unsafe {
|
||||||
|
from_utf8_unchecked(CStr::from_ptr((*self.ptr).name).to_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extensions<'a>(&'a self) -> Vec<&'a str> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (*self.ptr).extensions;
|
||||||
|
|
||||||
|
if ptr == ptr::null() {
|
||||||
|
vec!()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
from_utf8_unchecked(CStr::from_ptr(ptr).to_bytes()).split(',').collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mime_types<'a>(&'a self) -> Vec<&'a str> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (*self.ptr).mime_type;
|
||||||
|
|
||||||
|
if ptr == ptr::null() {
|
||||||
|
vec!()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
from_utf8_unchecked(CStr::from_ptr(ptr).to_bytes()).split(',').collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list() -> FormatIter {
|
||||||
|
FormatIter::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FormatIter {
|
||||||
|
input: *mut AVInputFormat,
|
||||||
|
output: *mut AVOutputFormat,
|
||||||
|
step: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormatIter {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
FormatIter { input: ptr::null_mut(), output: ptr::null_mut(), step: 0 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for FormatIter {
|
||||||
|
type Item = Format;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||||
|
unsafe {
|
||||||
|
match self.step {
|
||||||
|
0 => {
|
||||||
|
let ptr = av_iformat_next(self.input);
|
||||||
|
|
||||||
|
if ptr == ptr::null_mut() && self.input != ptr::null_mut() {
|
||||||
|
self.step = 1;
|
||||||
|
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.input = ptr;
|
||||||
|
|
||||||
|
Some(Format::Input(Input::wrap(ptr)))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
1 => {
|
||||||
|
let ptr = av_oformat_next(self.output);
|
||||||
|
|
||||||
|
if ptr == ptr::null_mut() && self.output != ptr::null_mut() {
|
||||||
|
self.step = 2;
|
||||||
|
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.output = ptr;
|
||||||
|
|
||||||
|
Some(Format::Output(Output::wrap(ptr)))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,39 @@
|
|||||||
pub use ::util::sample_format::SampleFormat as Sample;
|
pub use ::util::sample_format::SampleFormat as Sample;
|
||||||
pub use ::util::pixel_format::PixelFormat as Pixel;
|
pub use ::util::pixel_format::PixelFormat as Pixel;
|
||||||
|
|
||||||
|
pub mod stream;
|
||||||
|
|
||||||
|
pub mod context;
|
||||||
|
pub use self::context::{Context, open, open_with, open_as, open_as_with, dump};
|
||||||
|
|
||||||
|
pub mod format;
|
||||||
|
pub use self::format::{Input, Output, list};
|
||||||
|
|
||||||
pub mod network;
|
pub mod network;
|
||||||
|
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::str::from_utf8_unchecked;
|
use std::str::from_utf8_unchecked;
|
||||||
|
|
||||||
use ffi::*;
|
use ffi::*;
|
||||||
|
use ::Format;
|
||||||
|
|
||||||
|
pub fn register_all() {
|
||||||
|
unsafe {
|
||||||
|
av_register_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register(format: &Format) {
|
||||||
|
match format {
|
||||||
|
&Format::Input(ref format) => unsafe {
|
||||||
|
av_register_input_format(format.ptr);
|
||||||
|
},
|
||||||
|
|
||||||
|
&Format::Output(ref format) => unsafe {
|
||||||
|
av_register_output_format(format.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn version() -> u32 {
|
pub fn version() -> u32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
132
src/format/stream.rs
Normal file
132
src/format/stream.rs
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use libc::c_int;
|
||||||
|
use ffi::*;
|
||||||
|
use ::format;
|
||||||
|
use ::codec::{self, packet};
|
||||||
|
use ::{Rational, Discard};
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
flags Disposition: i32 {
|
||||||
|
const DISPOSITION_DEFAULT = AV_DISPOSITION_DEFAULT,
|
||||||
|
const DISPOSITION_DUB = AV_DISPOSITION_DUB,
|
||||||
|
const DISPOSITION_ORIGINAL = AV_DISPOSITION_ORIGINAL,
|
||||||
|
const DISPOSITION_COMMENT = AV_DISPOSITION_COMMENT,
|
||||||
|
const DISPOSITION_LYRICS = AV_DISPOSITION_LYRICS,
|
||||||
|
const DISPOSITION_KARAOKE = AV_DISPOSITION_KARAOKE,
|
||||||
|
const DISPOSITION_FORCED = AV_DISPOSITION_FORCED,
|
||||||
|
const DISPOSITION_HEARING_IMPAIRED = AV_DISPOSITION_HEARING_IMPAIRED,
|
||||||
|
const DISPOSITION_VISUAL_IMPAIRED = AV_DISPOSITION_VISUAL_IMPAIRED,
|
||||||
|
const DISPOSITION_CLEAN_EFFECTS = AV_DISPOSITION_CLEAN_EFFECTS,
|
||||||
|
const DISPOSITION_ATTACHED_PIC = AV_DISPOSITION_ATTACHED_PIC,
|
||||||
|
const DISPOSITION_CAPTIONS = AV_DISPOSITION_CAPTIONS,
|
||||||
|
const DISPOSITION_DESCRIPTIONS = AV_DISPOSITION_DESCRIPTIONS,
|
||||||
|
const DISPOSITION_METADATA = AV_DISPOSITION_METADATA,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
pub struct Stream<'a> {
|
||||||
|
ptr: *mut AVStream,
|
||||||
|
|
||||||
|
_marker: PhantomData<&'a format::Context<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Stream<'a> {
|
||||||
|
pub fn wrap(ptr: *mut AVStream) -> Self {
|
||||||
|
Stream { ptr: ptr, _marker: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn codec(&'a self) -> codec::Context<'a> {
|
||||||
|
unsafe {
|
||||||
|
codec::Context::wrap((*self.ptr).codec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
unsafe {
|
||||||
|
(*self.ptr).index as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn time_base(&self) -> Rational {
|
||||||
|
unsafe {
|
||||||
|
Rational((*self.ptr).time_base)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_time(&self) -> i64 {
|
||||||
|
unsafe {
|
||||||
|
(*self.ptr).start_time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn duration(&self) -> i64 {
|
||||||
|
unsafe {
|
||||||
|
(*self.ptr).duration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn frames(&self) -> i64 {
|
||||||
|
unsafe {
|
||||||
|
(*self.ptr).nb_frames
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disposition(&self) -> Disposition {
|
||||||
|
unsafe {
|
||||||
|
Disposition::from_bits_truncate((*self.ptr).disposition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn discard(&self) -> Discard {
|
||||||
|
unsafe {
|
||||||
|
Discard::from((*self.ptr).discard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn side_data(&'a self) -> SideDataIter<'a> {
|
||||||
|
SideDataIter::new(self.ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn frame_rate(&self) -> Rational {
|
||||||
|
unsafe {
|
||||||
|
Rational(av_stream_get_r_frame_rate(self.ptr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_frame_rate(&self, value: Rational) {
|
||||||
|
unsafe {
|
||||||
|
av_stream_set_r_frame_rate(self.ptr, value.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SideDataIter<'a> {
|
||||||
|
ptr: *mut AVStream,
|
||||||
|
cur: c_int,
|
||||||
|
|
||||||
|
_marker: PhantomData<&'a Stream<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SideDataIter<'a> {
|
||||||
|
pub fn new(ptr: *mut AVStream) -> Self {
|
||||||
|
SideDataIter { ptr: ptr, cur: 0, _marker: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for SideDataIter<'a> {
|
||||||
|
type Item = packet::SideData<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||||
|
unsafe {
|
||||||
|
if self.cur >= (*self.ptr).nb_side_data {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.cur += 1;
|
||||||
|
Some(packet::SideData::wrap((*self.ptr).side_data.offset((self.cur - 1) as isize)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,8 @@ pub use util::media;
|
|||||||
pub use util::frame::{self, Frame};
|
pub use util::frame::{self, Frame};
|
||||||
|
|
||||||
pub mod format;
|
pub mod format;
|
||||||
|
pub use format::format::Format;
|
||||||
|
pub use format::stream::Stream;
|
||||||
|
|
||||||
pub mod codec;
|
pub mod codec;
|
||||||
pub use codec::packet::{self, Packet};
|
pub use codec::packet::{self, Packet};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user