+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "assets.h"
-#include "file.inc"
-#include "language.h"
-#include "playbackconfig.h"
-#include "preferences.h"
-#include "recordconfig.h"
-#include "strategies.inc"
-#include "vdevicelml.h"
-#include "vframe.h"
-#include "videoconfig.h"
-#include "videodevice.h"
-
-
-#define SOI 0xffd8
-#define APP3 0xffe3
-#define APP1 0xffe1
-#define APP0 0xffe0
-#define EOI 0xffd9
-
-VDeviceLML::VDeviceLML(VideoDevice *device)
- : VDeviceBase(device)
-{
- reset_parameters();
- render_strategies.append(VRENDER_MJPG);
-}
-
-VDeviceLML::~VDeviceLML()
-{
- close_all();
-}
-
-int VDeviceLML::reset_parameters()
-{
- jvideo_fd = 0;
- input_buffer = 0;
- frame_buffer = 0;
- frame_size = 0;
- frame_allocated = 0;
- input_error = 0;
- input_position = INPUT_BUFFER_SIZE;
- last_frame_no = 0;
-}
-
-int VDeviceLML::open_input()
-{
- jvideo_fd = fopen(device->in_config->lml_in_device, "rb");
- if(jvideo_fd)
- {
- return 0;
- }
- else
- {
- perror("VDeviceLML::open_input");
- jvideo_fd = 0;
- return 1;
- }
- return 0;
-}
-
-int VDeviceLML::open_output()
-{
- jvideo_fd = fopen(device->out_config->lml_out_device, "wb");
- if(jvideo_fd)
- {
- return 0;
- }
- else
- {
- perror("VDeviceLML::open_output");
- jvideo_fd = 0;
- return 1;
- }
- return 0;
-}
-
-int VDeviceLML::close_all()
-{
- if(device->r)
- {
- if(jvideo_fd) fclose(jvideo_fd);
- }
- if(device->w)
- {
- if(jvideo_fd) fclose(jvideo_fd);
- }
- if(input_buffer)
- {
- delete input_buffer;
- }
- if(frame_buffer)
- {
- delete frame_buffer;
- }
- reset_parameters();
- return 0;
-}
-
-int VDeviceLML::read_buffer(VFrame *frame)
-{
- long first_field = 0, frame1_size = 0, frame2_size = 0, i;
- int result = 0, frame_no = 0, retries = 0;
-
- if(!jvideo_fd) return 1;
-
- input_error = 0;
-
-retry:
- frame->set_compressed_size(0);
- retries++;
- if(retries > 5) return 1;
-
-// Keep reading until the first field of a frame arrives.
- while(!input_error && !first_field)
- {
-// Get the first marker of a frame
- while(!input_error && next_bytes(2) != SOI)
- {
- get_byte();
- }
-
-// Store SOI marker
- frame_size = 0;
- write_byte(get_byte());
- write_byte(get_byte());
-
-// Copy the first frame
- while(!input_error && next_bytes(2) != EOI)
- {
-// Replace the LML header with a Quicktime header
- if(next_bytes(2) == APP3)
- {
- first_field = 1;
- write_fake_marker();
-
- get_byte(); // APP3
- get_byte();
- get_byte(); // LEN
- get_byte();
- get_byte(); // COMMENT
- get_byte();
- get_byte();
- get_byte();
- get_byte(); // Frame no
- get_byte();
- get_byte(); // sec
- get_byte();
- get_byte();
- get_byte();
- get_byte(); // usec
- get_byte();
- get_byte();
- get_byte();
- get_byte(); // framesize (useless since we have to swap frames)
- get_byte();
- get_byte();
- get_byte();
- frame_no = get_byte(); // frame seq no
- frame_no |= (long)get_byte() << 8;
- frame_no |= (long)get_byte() << 16;
- frame_no |= (long)get_byte() << 24;
-
- if(frame_no <= last_frame_no)
- {
- input_error = reopen_input();
- first_field = 0;
- goto retry;
- }
- else
- {
-// Finish LML header
- last_frame_no = frame_no;
- while(next_bytes(2) != 0xffdb) get_byte();
- }
- }
- else
- {
- write_byte(get_byte());
- }
- }
-
-// Store EOI marker
- write_byte(get_byte());
- write_byte(get_byte());
- }
-
- frame1_size = frame_size;
-
-// Read the second field
- if(first_field)
- {
-// Find next field
- while(!input_error && next_bytes(2) != SOI)
- {
- get_byte();
- }
-
-// Store SOI marker
- write_byte(get_byte());
- write_byte(get_byte());
-
-// Store Quicktime header
- write_fake_marker();
-
-// Copy the second frame
- while(!input_error && next_bytes(2) != EOI)
- {
- write_byte(get_byte());
- }
-
-// Store EOI marker
- write_byte(get_byte());
- write_byte(get_byte());
- }
-
- frame2_size = frame_size - frame1_size;
-
-// Insert the required information
- if(!input_error)
- {
-// Store in the VFrame
- frame->allocate_compressed_data(frame_size);
-
-// Quicktime expects the even field first
- if(device->odd_field_first)
- {
- memcpy(frame->get_data(), frame_buffer + frame1_size, frame2_size);
- memcpy(frame->get_data() + frame2_size, frame_buffer, frame1_size);
- }
- else
- memcpy(frame->get_data(), frame_buffer, frame_size);
-
- frame->set_compressed_size(frame_size);
- }
- else
- {
- input_error = 0;
- reopen_input();
- goto retry;
- }
-
- return input_error;
-}
-
-int VDeviceLML::reopen_input()
-{
- int input_error = 0;
- Timer timer;
- fprintf(stderr, _("VDeviceLML::read_buffer: driver crash\n"));
- fclose(jvideo_fd);
- timer.delay(100);
- input_error = open_input();
- if(!input_error) fprintf(stderr, _("VDeviceLML::read_buffer: reopened\n"));
- last_frame_no = 0;
- input_position = INPUT_BUFFER_SIZE;
- return input_error;
-}
-
-
-int VDeviceLML::write_fake_marker()
-{
-// Marker
- write_byte(0xff);
- write_byte(0xe1);
-// Size
- write_byte(0x00);
- write_byte(0x2a);
-// Blank space
- for(int i = 0; i < 0x28; i++)
- {
- write_byte(0x00);
- }
- return 0;
-}
-
-int VDeviceLML::refill_input()
-{
-// Shift remaining data up.
- memcpy(input_buffer, input_buffer + input_position, INPUT_BUFFER_SIZE - input_position);
-
-// Append new data
- input_error = !fread(input_buffer + INPUT_BUFFER_SIZE - input_position,
- INPUT_BUFFER_SIZE - (INPUT_BUFFER_SIZE - input_position),
- 1,
- jvideo_fd);
-
- input_position = 0;
- return input_error;
-}
-
-
-int VDeviceLML::write_buffer(VFrame *frame, EDL *edl)
-{
- int result = 0, i, frame1size, j, size_qword, real_size, skip;
- unsigned long size = frame->get_compressed_size();
- unsigned char *data = frame->get_data();
- unsigned char *data1;
- int even_field_first = 1;
-
-#if 0
- if(!jvideo_fd || frame->get_color_model() != VFRAME_COMPRESSED) return 1;
-#endif
-
- if(frame_allocated < size * 2)
- {
- delete frame_buffer;
- frame_buffer = 0;
- }
-
- if(!frame_buffer)
- {
- frame_buffer = new unsigned char[size * 2];
- }
-
- for(data1 = data + 1, i = 0; i < size - 1; i++)
- if(data[i] == ((EOI & 0xff00) >> 8) && data1[i] == (EOI & 0xff)) break;
-
- i += 2;
- frame1size = i;
- j = 0;
- if(even_field_first) i = 0;
-
-// SOI
- frame_buffer[j++] = data[i++];
- frame_buffer[j++] = data[i++];
-
-// APP3 for LML driver
- frame_buffer[j++] = (APP3 & 0xff00) >> 8;
- frame_buffer[j++] = APP3 & 0xff;
- frame_buffer[j++] = 0; // Marker size
- frame_buffer[j++] = 0x2c;
- frame_buffer[j++] = 'L'; // nm
- frame_buffer[j++] = 'M';
- frame_buffer[j++] = 'L';
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0; // frameNo
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0; // sec
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0; // usec
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
-// Frame size eventually goes here
- size_qword = j;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
-// Frame Seq No
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
-// Color Encoding
- frame_buffer[j++] = 1;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
-// Video Stream
- frame_buffer[j++] = 1;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
-// Time Decimation
- frame_buffer[j++] = 1;
- frame_buffer[j++] = 0;
-// Filler
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
- frame_buffer[j++] = 0;
-
-// Copy rest of first field
- data1 = data + 1;
-
- while(i < size)
- {
- frame_buffer[j++] = data[i++];
- }
-
-// Copy second field
- if(!even_field_first)
- {
- for(i = 0; i < frame1size; )
- {
- frame_buffer[j++] = data[i++];
- }
- }
-
- real_size = j;
-// frameSize in little endian
- frame_buffer[size_qword++] = (real_size & 0xff);
- frame_buffer[size_qword++] = ((real_size & 0xff00) >> 8);
- frame_buffer[size_qword++] = ((real_size & 0xff0000) >> 16);
- frame_buffer[size_qword++] = ((real_size & 0xff000000) >> 24);
-
-//fwrite(frame_buffer, real_size, 1, stdout);
- result = !fwrite(frame_buffer,
- real_size,
- 1,
- jvideo_fd);
- if(result) perror("VDeviceLML::write_buffer");
-
- return result;
-}
-
-ArrayList<int>* VDeviceLML::get_render_strategies()
-{
- return &render_strategies;
-}