int FileJPEG::check_sig(Asset *asset)
{
- FILE *stream = fopen(asset->path, "rb");
-
- if(stream)
- {
- char test[10];
- (void)fread(test, 10, 1, stream);
- fclose(stream);
-
- if(test[6] == 'J' && test[7] == 'F' && test[8] == 'I' && test[9] == 'F')
- {
- return 1;
+ FILE *fp = fopen(asset->path, "r");
+ if( !fp ) return 0;
+ char test[10];
+ int result = -1;
+ if( fread(test, 1, sizeof(test), fp) == sizeof(test) ) {
+ if( test[6] == 'J' && test[7] == 'F' && test[8] == 'I' && test[9] == 'F' ) {
+ fseek(fp, 0, SEEK_SET);
+ int w = 0, h = 0;
+ result = read_header(fp, w, h);
}
- else
- if(test[0] == 'J' && test[1] == 'P' && test[2] == 'E' && test[3] == 'G' &&
- test[4] == 'L' && test[5] == 'I' && test[6] == 'S' && test[7] == 'T')
- {
- return 1;
+ else if(test[0] == 'J' && test[1] == 'P' && test[2] == 'E' && test[3] == 'G' &&
+ test[4] == 'L' && test[5] == 'I' && test[6] == 'S' && test[7] == 'T') {
+ result = 0;
}
}
+ fclose(fp);
- if(strlen(asset->path) > 4)
- {
- int len = strlen(asset->path);
- if(!strncasecmp(asset->path + len - 4, ".jpg", 4)) return 1;
+ if( result < 0 ) {
+ int i = strlen(asset->path) - 4;
+ if( i >= 0 && !strcasecmp(asset->path+i, ".jpg") )
+ result = 0;
}
- return 0;
+ return !result ? 1 : 0;
}
-
void FileJPEG::get_parameters(BC_WindowBase *parent_window,
- Asset *asset,
- BC_WindowBase* &format_window,
- int audio_options,
- int video_options)
+ Asset *asset, BC_WindowBase* &format_window,
+ int audio_options, int video_options, EDL *edl)
{
if(video_options)
{
case PLAYBACK_X11_GL:
return BC_YUV888;
break;
- case PLAYBACK_LML:
- case PLAYBACK_BUZ:
- return BC_YUV422P;
- break;
- case VIDEO4LINUX:
case VIDEO4LINUX2:
return BC_YUV420P;
break;
- case CAPTURE_BUZ:
- case CAPTURE_LML:
case VIDEO4LINUX2JPEG:
return BC_YUV422;
break;
frame->get_color_model(),
1);
+// insert spherical tag
+ if(asset->jpeg_sphere)
+ {
+ const char *sphere_tag =
+ "http://ns.adobe.com/xap/1.0/\x00<?xpacket begin='\xef\xbb\xbf' id='W5M0MpCehiHzreSzNTczkc9d'?>\n"
+ "<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::Cinelerra'>\n"
+ "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n"
+ "\n"
+ " <rdf:Description rdf:about=''\n"
+ " xmlns:GPano='http://ns.google.com/photos/1.0/panorama/'>\n"
+ " <GPano:ProjectionType>equirectangular</GPano:ProjectionType>\n"
+ " </rdf:Description>\n"
+ "</rdf:RDF>\n"
+ "</x:xmpmeta>\n"
+ "<?xpacket end='w'?>";
+
+// calculate length by skipping the \x00 byte
+ int skip = 32;
+ int tag_len = strlen(sphere_tag + skip) + skip;
+ int tag_len2 = tag_len + 2;
+ int tag_len3 = tag_len + 4;
+
+ data->allocate_compressed_data(
+ mjpeg_output_size((mjpeg_t*)jpeg_unit->compressor) + tag_len3);
+ data->set_compressed_size(
+ mjpeg_output_size((mjpeg_t*)jpeg_unit->compressor) + tag_len3);
+
+ int jfif_size = 0x14;
+ uint8_t *ptr = data->get_data();
+ memcpy(ptr,
+ mjpeg_output_buffer((mjpeg_t*)jpeg_unit->compressor),
+ jfif_size);
+ ptr += jfif_size;
+ *ptr++ = 0xff;
+ *ptr++ = 0xe1;
+ *ptr++ = (tag_len2 >> 8) & 0xff;
+ *ptr++ = tag_len2 & 0xff;
+ memcpy(ptr,
+ sphere_tag,
+ tag_len);
+ ptr += tag_len;
+ memcpy(ptr,
+ mjpeg_output_buffer((mjpeg_t*)jpeg_unit->compressor) + jfif_size,
+ mjpeg_output_size((mjpeg_t*)jpeg_unit->compressor) - jfif_size);
+ }
+ else
+ {
+ data->allocate_compressed_data(mjpeg_output_size((mjpeg_t*)jpeg_unit->compressor));
+ data->set_compressed_size(mjpeg_output_size((mjpeg_t*)jpeg_unit->compressor));
+ memcpy(data->get_data(),
+ mjpeg_output_buffer((mjpeg_t*)jpeg_unit->compressor),
+ mjpeg_output_size((mjpeg_t*)jpeg_unit->compressor));
+ }
data->allocate_compressed_data(mjpeg_output_size((mjpeg_t*)jpeg_unit->compressor));
data->set_compressed_size(mjpeg_output_size((mjpeg_t*)jpeg_unit->compressor));
memcpy(data->get_data(),
int FileJPEG::read_frame_header(char *path)
{
- int result = 0;
-
-
- FILE *stream;
-
- if(!(stream = fopen(path, "rb")))
- {
+ FILE *fp = fopen(path, "rb");
+ if( !fp ) {
eprintf("FileJPEG::read_frame_header %s: %m\n", path);
return 1;
}
-
-
+ int w = 0, h = 0, result = 1;
unsigned char test[2];
- (void)fread(test, 2, 1, stream);
- if(test[0] != 0xff || test[1] != 0xd8)
- {
- eprintf("FileJPEG::read_frame_header %s bad header %02x%02x\n",
- path, test[0], test[1]);
- fclose(stream);
- return 1;
+ if( fread(test, 1, sizeof(test), fp) == sizeof(test) &&
+ test[0] == 0xff && test[1] == 0xd8 ) {
+ fseek(fp, 0, SEEK_SET);
+ result = read_header(fp, w, h);
+ }
+ fclose(fp);
+ if( !result ) {
+ asset->width = w; asset->height = h;
+ asset->interlace_mode = ILACE_MODE_NOTINTERLACED;
}
- fseek(stream, 0, SEEK_SET);
+ else
+ eprintf("FileJPEG::read_frame_header %s bad header\n", path);
+ return result;
+}
- struct jpeg_decompress_struct jpeg_decompress;
+int FileJPEG::read_header(FILE *fp, int &w, int &h)
+{
+ int result = 0;
struct jpeg_error_mgr jpeg_error;
-
+ struct jpeg_decompress_struct jpeg_decompress;
jpeg_decompress.err = jpeg_std_error(&jpeg_error);
jpeg_create_decompress(&jpeg_decompress);
-
- jpeg_stdio_src(&jpeg_decompress, stream);
- jpeg_read_header(&jpeg_decompress, TRUE);
-
- asset->width = jpeg_decompress.image_width;
- asset->height = jpeg_decompress.image_height;
-
- asset->interlace_mode = BC_ILACE_MODE_NOTINTERLACED;
-
+ jpeg_stdio_src(&jpeg_decompress, fp);
+ if( jpeg_read_header(&jpeg_decompress, TRUE) != JPEG_HEADER_OK ) result = 1;
+ if( !result && jpeg_decompress.jpeg_color_space != JCS_YCbCr ) result = 1;
+ if( !result && jpeg_decompress.comp_info[0].h_samp_factor > 2 ) result = 1;
+ if( !result && jpeg_decompress.comp_info[0].v_samp_factor > 2 ) result = 1;
+ if( !result ) {
+ w = jpeg_decompress.image_width;
+ h = jpeg_decompress.image_height;
+ }
jpeg_destroy((j_common_ptr)&jpeg_decompress);
- fclose(stream);
-
return result;
}
-
int FileJPEG::read_frame(VFrame *output, VFrame *input)
{
if(input->get_compressed_size() < 2 ||
JPEGConfigVideo::JPEGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
- : BC_Window(PROGRAM_NAME ": Video Compression",
+ : BC_Window(_(PROGRAM_NAME ": Video Compression"),
parent_window->get_abs_cursor_x(1),
parent_window->get_abs_cursor_y(1),
- 400,
- 100)
+ 400, 200)
{
this->parent_window = parent_window;
this->asset = asset;
int x = 10, y = 10;
lock_window("JPEGConfigVideo::create_objects");
add_subwindow(new BC_Title(x, y, _("Quality:")));
- add_subwindow(new BC_ISlider(x + 80,
- y,
- 0,
- 200,
- 200,
- 0,
- 100,
- asset->jpeg_quality,
- 0,
- 0,
+ BC_ISlider *slider;
+ add_subwindow(slider = new BC_ISlider(x + 80, y,
+ 0, 200, 200, 0, 100, asset->jpeg_quality, 0, 0,
&asset->jpeg_quality));
+ y += slider->get_h() + 10;
+ add_subwindow(new BC_CheckBox(x, y,
+ &asset->jpeg_sphere, _("Tag for spherical playback")));
add_subwindow(new BC_OKButton(this));
show_window(1);